mirror of
https://git.asonix.dog/asonix/pict-rs.git
synced 2024-11-04 16:49:41 +00:00
122 lines
3.1 KiB
Rust
122 lines
3.1 KiB
Rust
|
use diesel::{backend::Backend, sql_types::VarChar, AsExpression, FromSqlRow};
|
||
|
use uuid::Uuid;
|
||
|
|
||
|
use super::MaybeUuid;
|
||
|
|
||
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, AsExpression, FromSqlRow)]
|
||
|
#[diesel(sql_type = VarChar)]
|
||
|
pub(crate) struct Alias {
|
||
|
id: MaybeUuid,
|
||
|
extension: Option<String>,
|
||
|
}
|
||
|
|
||
|
impl diesel::serialize::ToSql<VarChar, diesel::pg::Pg> for Alias {
|
||
|
fn to_sql<'b>(
|
||
|
&'b self,
|
||
|
out: &mut diesel::serialize::Output<'b, '_, diesel::pg::Pg>,
|
||
|
) -> diesel::serialize::Result {
|
||
|
let s = self.to_string();
|
||
|
|
||
|
<String as diesel::serialize::ToSql<VarChar, diesel::pg::Pg>>::to_sql(
|
||
|
&s,
|
||
|
&mut out.reborrow(),
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<B> diesel::deserialize::FromSql<VarChar, B> for Alias
|
||
|
where
|
||
|
B: Backend,
|
||
|
String: diesel::deserialize::FromSql<VarChar, B>,
|
||
|
{
|
||
|
fn from_sql(
|
||
|
bytes: <B as diesel::backend::Backend>::RawValue<'_>,
|
||
|
) -> diesel::deserialize::Result<Self> {
|
||
|
let s = String::from_sql(bytes)?;
|
||
|
|
||
|
s.parse().map_err(From::from)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Alias {
|
||
|
pub(crate) fn generate(extension: String) -> Self {
|
||
|
Alias {
|
||
|
id: MaybeUuid::Uuid(Uuid::new_v4()),
|
||
|
extension: Some(extension),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub(crate) fn from_existing(alias: &str) -> Self {
|
||
|
if let Some((start, end)) = split_at_dot(alias) {
|
||
|
Alias {
|
||
|
id: MaybeUuid::from_str(start),
|
||
|
extension: Some(end.into()),
|
||
|
}
|
||
|
} else {
|
||
|
Alias {
|
||
|
id: MaybeUuid::from_str(alias),
|
||
|
extension: None,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub(crate) fn extension(&self) -> Option<&str> {
|
||
|
self.extension.as_deref()
|
||
|
}
|
||
|
|
||
|
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||
|
let mut v = self.id.as_bytes().to_vec();
|
||
|
|
||
|
if let Some(ext) = self.extension() {
|
||
|
v.extend_from_slice(ext.as_bytes());
|
||
|
}
|
||
|
|
||
|
v
|
||
|
}
|
||
|
|
||
|
pub(crate) fn from_slice(bytes: &[u8]) -> Option<Self> {
|
||
|
if let Ok(s) = std::str::from_utf8(bytes) {
|
||
|
Some(Self::from_existing(s))
|
||
|
} else if bytes.len() >= 16 {
|
||
|
let id = Uuid::from_slice(&bytes[0..16]).expect("Already checked length");
|
||
|
|
||
|
let extension = if bytes.len() > 16 {
|
||
|
Some(String::from_utf8_lossy(&bytes[16..]).to_string())
|
||
|
} else {
|
||
|
None
|
||
|
};
|
||
|
|
||
|
Some(Self {
|
||
|
id: MaybeUuid::Uuid(id),
|
||
|
extension,
|
||
|
})
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn split_at_dot(s: &str) -> Option<(&str, &str)> {
|
||
|
let index = s.find('.')?;
|
||
|
|
||
|
Some(s.split_at(index))
|
||
|
}
|
||
|
|
||
|
impl std::str::FromStr for Alias {
|
||
|
type Err = std::convert::Infallible;
|
||
|
|
||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
|
Ok(Alias::from_existing(s))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl std::fmt::Display for Alias {
|
||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
|
if let Some(ext) = self.extension() {
|
||
|
write!(f, "{}{ext}", self.id)
|
||
|
} else {
|
||
|
write!(f, "{}", self.id)
|
||
|
}
|
||
|
}
|
||
|
}
|