//! Universally unique identifier //! //! Wrapper around `Uuid` to store it as text in sql table. use std::cmp::{Eq, PartialEq}; use std::fmt; use std::hash::{Hash, Hasher}; use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef}; use serde::{Deserialize, Serialize}; use uuid::Uuid; /// Universally unique identifier #[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub struct Id(Uuid); impl Id { /// Return a newly generated `Id` pub fn new() -> Self { Self(Uuid::new_v4()) } } impl fmt::Display for Id { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } impl Hash for Id { fn hash(&self, state: &mut H) { self.0.hash(state); } } impl Into for Id { fn into(self) -> Uuid { self.0 } } impl From for Id { fn from(u: Uuid) -> Self { Self(u) } } impl Eq for Id {} impl PartialEq for Id { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } impl FromSql for Id { fn column_result(value: ValueRef<'_>) -> FromSqlResult { let s = match value.as_str() { Ok(s) => s, Err(e) => { log::error!("{}({}) :: {} :: {}", file!(), line!(), "value.as_str()", e); return Err(e); } }; match Uuid::parse_str(s) { Ok(id) => return Ok(Self(id)), Err(e) => Err(FromSqlError::Other(Box::from(e))), } } } impl ToSql for Id { fn to_sql(&self) -> rusqlite::Result> { let h = self.0.to_hyphenated(); let mut buf = Uuid::encode_buffer(); let s = h.encode_lower(&mut buf); Ok(ToSqlOutput::from(s.to_string())) } }