mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-18 14:31:30 +03:00
119 lines
2.6 KiB
Rust
119 lines
2.6 KiB
Rust
|
//! A generic UUID-based wrapper, via a newtype pattern
|
||
|
//! with a few key integrations used throughout the library.
|
||
|
|
||
|
use std::{fmt, hash::Hash, marker::PhantomData, str};
|
||
|
|
||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||
|
use uuid::Uuid;
|
||
|
|
||
|
/// A generic UUID-based newtype.
|
||
|
///
|
||
|
/// `Default` is implemented to generate a new UUID
|
||
|
/// via [`Uuid::new_v4`].
|
||
|
pub struct Id<T>(Uuid, PhantomData<T>);
|
||
|
|
||
|
impl<T> Hash for Id<T> {
|
||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||
|
self.0.hash(state);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> PartialOrd for Id<T> {
|
||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||
|
Some(self.cmp(other))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> Ord for Id<T> {
|
||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||
|
self.0.cmp(&other.0)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> Id<T> {
|
||
|
#[must_use]
|
||
|
pub fn generate() -> Self {
|
||
|
Id(Uuid::new_v4(), PhantomData)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> Default for Id<T> {
|
||
|
fn default() -> Self {
|
||
|
Self::generate()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> rusqlite::types::FromSql for Id<T> {
|
||
|
fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
|
||
|
Uuid::parse_str(value.as_str()?)
|
||
|
.map(Into::into)
|
||
|
.map_err(|error| rusqlite::types::FromSqlError::Other(Box::new(error)))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> rusqlite::ToSql for Id<T> {
|
||
|
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
|
||
|
Ok(rusqlite::types::ToSqlOutput::from(self.0.to_string()))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> PartialEq for Id<T> {
|
||
|
fn eq(&self, other: &Self) -> bool {
|
||
|
self.0.eq(&other.0)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> Eq for Id<T> {}
|
||
|
|
||
|
impl<T> From<Uuid> for Id<T> {
|
||
|
fn from(value: Uuid) -> Self {
|
||
|
Self(value, PhantomData)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<'de, T> Deserialize<'de> for Id<T> {
|
||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||
|
where
|
||
|
D: Deserializer<'de>,
|
||
|
{
|
||
|
Uuid::deserialize(deserializer).map(Into::into)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> Serialize for Id<T> {
|
||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||
|
where
|
||
|
S: Serializer,
|
||
|
{
|
||
|
self.0.serialize(serializer)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> Clone for Id<T> {
|
||
|
fn clone(&self) -> Self {
|
||
|
*self
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> fmt::Display for Id<T> {
|
||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
|
self.0.fmt(f)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> fmt::Debug for Id<T> {
|
||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
|
self.0.fmt(f)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> Copy for Id<T> {}
|
||
|
|
||
|
impl<T> str::FromStr for Id<T> {
|
||
|
type Err = uuid::Error;
|
||
|
|
||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
|
Uuid::parse_str(s).map(Into::into)
|
||
|
}
|
||
|
}
|