use std::convert::TryFrom; use std::fmt::{Debug, Formatter}; use std::io::Write; use std::str::FromStr; use diesel::backend::Backend; use diesel::deserialize::FromSql; use diesel::serialize::{IsNull, Output, ToSql}; use diesel::sql_types::Binary; use diesel::sqlite::Sqlite; use diesel::{deserialize, serialize}; use serde::{Serialize, Serializer}; use uuid::Uuid; #[derive(AsExpression, FromSqlRow, PartialEq, Clone)] #[sql_type = "Binary"] pub enum EmgauwaUid { Off, On, Any(Uuid), } impl EmgauwaUid { const OFF_STR: &'static str = "off"; const ON_STR: &'static str = "on"; const OFF_U8: u8 = 0; const ON_U8: u8 = 1; const OFF_U128: u128 = 0; const ON_U128: u128 = 1; } impl Default for EmgauwaUid { fn default() -> Self { EmgauwaUid::Any(Uuid::new_v4()) } } impl Debug for EmgauwaUid { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { EmgauwaUid::Off => EmgauwaUid::OFF_STR.fmt(f), EmgauwaUid::On => EmgauwaUid::ON_STR.fmt(f), EmgauwaUid::Any(value) => value.fmt(f), } } } impl ToSql for EmgauwaUid { fn to_sql(&self, out: &mut Output) -> serialize::Result { match self { EmgauwaUid::Off => out.write_all(&[EmgauwaUid::OFF_U8])?, EmgauwaUid::On => out.write_all(&[EmgauwaUid::ON_U8])?, EmgauwaUid::Any(value) => out.write_all(value.as_bytes())?, } Ok(IsNull::No) } } impl FromSql for EmgauwaUid { fn from_sql(bytes: Option<&::RawValue>) -> deserialize::Result { match bytes { None => Ok(EmgauwaUid::default()), Some(value) => match value.read_blob() { [EmgauwaUid::OFF_U8] => Ok(EmgauwaUid::Off), [EmgauwaUid::ON_U8] => Ok(EmgauwaUid::On), value_bytes => Ok(EmgauwaUid::Any(Uuid::from_slice(value_bytes).unwrap())), }, } } } impl Serialize for EmgauwaUid { fn serialize(&self, serializer: S) -> Result where S: Serializer, { String::from(self).serialize(serializer) } } impl From for EmgauwaUid { fn from(uid: Uuid) -> EmgauwaUid { match uid.as_u128() { EmgauwaUid::OFF_U128 => EmgauwaUid::Off, EmgauwaUid::ON_U128 => EmgauwaUid::On, _ => EmgauwaUid::Any(uid), } } } impl TryFrom<&str> for EmgauwaUid { type Error = uuid::Error; fn try_from(value: &str) -> Result { match value { EmgauwaUid::OFF_STR => Ok(EmgauwaUid::Off), EmgauwaUid::ON_STR => Ok(EmgauwaUid::On), any => match Uuid::from_str(any) { Ok(uuid) => Ok(EmgauwaUid::Any(uuid)), Err(err) => Err(err), }, } } } impl From<&EmgauwaUid> for Uuid { fn from(emgauwa_uid: &EmgauwaUid) -> Uuid { match emgauwa_uid { EmgauwaUid::Off => uuid::Uuid::from_u128(EmgauwaUid::OFF_U128), EmgauwaUid::On => uuid::Uuid::from_u128(EmgauwaUid::ON_U128), EmgauwaUid::Any(value) => *value, } } } impl From<&EmgauwaUid> for String { fn from(emgauwa_uid: &EmgauwaUid) -> String { match emgauwa_uid { EmgauwaUid::Off => String::from(EmgauwaUid::OFF_STR), EmgauwaUid::On => String::from(EmgauwaUid::ON_STR), EmgauwaUid::Any(value) => value.to_hyphenated().to_string(), } } }