pub mod schemas;
use crate::metadata::ConstId;
use core::fmt;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use hex::ToHex;
use zerocopy::Immutable;
use zerocopy::IntoBytes;
use zerocopy::KnownLayout;
use zerocopy::TryFromBytes;
use zerocopy::Unaligned;
pub const VALUE_LEN: usize = 32;
pub type RawValue = [u8; VALUE_LEN];
#[derive(TryFromBytes, IntoBytes, Unaligned, Immutable, KnownLayout)]
#[repr(transparent)]
pub struct Value<T: ValueSchema> {
pub raw: RawValue,
_schema: PhantomData<T>,
}
impl<S: ValueSchema> Value<S> {
pub fn new(value: RawValue) -> Self {
Self {
raw: value,
_schema: PhantomData,
}
}
pub fn validate(self) -> Result<Self, S::ValidationError> {
S::validate(self)
}
pub fn is_valid(&self) -> bool {
S::validate(*self).is_ok()
}
pub fn transmute<O>(self) -> Value<O>
where
O: ValueSchema,
{
Value::new(self.raw)
}
pub fn as_transmute<O>(&self) -> &Value<O>
where
O: ValueSchema,
{
unsafe { std::mem::transmute(self) }
}
pub fn as_transmute_raw(value: &RawValue) -> &Self {
unsafe { std::mem::transmute(value) }
}
pub fn from_value<'a, T>(&'a self) -> T
where
T: TryFromValue<'a, S, Error = std::convert::Infallible>,
{
match <T as TryFromValue<'a, S>>::try_from_value(self) {
Ok(v) => v,
Err(e) => match e {},
}
}
pub fn try_from_value<'a, T>(&'a self) -> Result<T, <T as TryFromValue<'a, S>>::Error>
where
T: TryFromValue<'a, S>,
{
<T as TryFromValue<'a, S>>::try_from_value(self)
}
}
impl<T: ValueSchema> Copy for Value<T> {}
impl<T: ValueSchema> Clone for Value<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ValueSchema> PartialEq for Value<T> {
fn eq(&self, other: &Self) -> bool {
self.raw == other.raw
}
}
impl<T: ValueSchema> Eq for Value<T> {}
impl<T: ValueSchema> Hash for Value<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.raw.hash(state);
}
}
impl<T: ValueSchema> Ord for Value<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.raw.cmp(&other.raw)
}
}
impl<T: ValueSchema> PartialOrd for Value<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<S: ValueSchema> Borrow<RawValue> for Value<S> {
fn borrow(&self) -> &RawValue {
&self.raw
}
}
impl<T: ValueSchema> Debug for Value<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Value<{}>({})",
std::any::type_name::<T>(),
ToHex::encode_hex::<String>(&self.raw)
)
}
}
pub trait ValueSchema: ConstId + Sized + 'static {
type ValidationError;
fn validate(value: Value<Self>) -> Result<Value<Self>, Self::ValidationError> {
Ok(value)
}
fn value_from<T: ToValue<Self>>(t: T) -> Value<Self> {
t.to_value()
}
fn value_try_from<T: TryToValue<Self>>(
t: T,
) -> Result<Value<Self>, <T as TryToValue<Self>>::Error> {
t.try_to_value()
}
}
pub trait ToValue<S: ValueSchema> {
fn to_value(self) -> Value<S>;
}
pub trait TryToValue<S: ValueSchema> {
type Error;
fn try_to_value(self) -> Result<Value<S>, Self::Error>;
}
pub trait TryFromValue<'a, S: ValueSchema>: Sized {
type Error;
fn try_from_value(v: &'a Value<S>) -> Result<Self, Self::Error>;
}
impl<S: ValueSchema> ToValue<S> for Value<S> {
fn to_value(self) -> Value<S> {
self
}
}
impl<S: ValueSchema> ToValue<S> for &Value<S> {
fn to_value(self) -> Value<S> {
*self
}
}
impl<'a, S: ValueSchema> TryFromValue<'a, S> for Value<S> {
type Error = std::convert::Infallible;
fn try_from_value(v: &'a Value<S>) -> Result<Self, std::convert::Infallible> {
Ok(*v)
}
}
impl<'a, S: ValueSchema> TryFromValue<'a, S> for () {
type Error = std::convert::Infallible;
fn try_from_value(_v: &'a Value<S>) -> Result<Self, std::convert::Infallible> {
Ok(())
}
}