|
|
|
@ -13,7 +13,7 @@ pub trait FormatSpec
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A strongly validated string slice
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
|
#[repr(transparent)]
|
|
|
|
|
pub struct FormattedStr<F: FormatSpec + ?Sized>(PhantomData<*const F>, str);
|
|
|
|
|
|
|
|
|
@ -22,10 +22,70 @@ unsafe impl<F: FormatSpec + ?Sized> std::marker::Send for FormattedStr<F>{}
|
|
|
|
|
unsafe impl<F: FormatSpec + ?Sized> std::marker::Sync for FormattedStr<F>{}
|
|
|
|
|
|
|
|
|
|
/// A strongly validated string
|
|
|
|
|
// TODO: How to perform validation on deserialise?
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
|
|
|
|
// TODO: How to perform validation on deserialise? Custom `Deserialize` impl? might have to.
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
|
pub struct FormattedString<F: FormatSpec + ?Sized>(String, PhantomData<F>);
|
|
|
|
|
|
|
|
|
|
// Deserialising
|
|
|
|
|
const _:() = {
|
|
|
|
|
use serde::{
|
|
|
|
|
de::Visitor,
|
|
|
|
|
de::Error,
|
|
|
|
|
de,
|
|
|
|
|
Serialize,
|
|
|
|
|
ser::Serializer,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
impl<F: FormatSpec + ?Sized> Serialize for FormattedStr<F>
|
|
|
|
|
{
|
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
|
where
|
|
|
|
|
S: Serializer,
|
|
|
|
|
{
|
|
|
|
|
serializer.serialize_str(&self.1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
impl<F: FormatSpec + ?Sized> Serialize for FormattedString<F>
|
|
|
|
|
{
|
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
|
where
|
|
|
|
|
S: Serializer,
|
|
|
|
|
{
|
|
|
|
|
serializer.serialize_str(&self.0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
struct FormattedStringVisitor<F: FormatSpec + ?Sized>(PhantomData<F>);
|
|
|
|
|
|
|
|
|
|
impl<'de, F: FormatSpec + ?Sized> Visitor<'de> for FormattedStringVisitor<F>
|
|
|
|
|
{
|
|
|
|
|
type Value = FormattedString<F>;
|
|
|
|
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
|
|
|
{
|
|
|
|
|
write!(f, "a string satisfying the requirements of {}", std::any::type_name::<F>())
|
|
|
|
|
}
|
|
|
|
|
fn visit_str<E: Error>(self, s: &str) -> Result<Self::Value, E>
|
|
|
|
|
{
|
|
|
|
|
FormattedStr::<F>::new(s).map_err(|x| E::custom(x.into())).map(ToOwned::to_owned)
|
|
|
|
|
}
|
|
|
|
|
fn visit_string<E: Error>(self, s: String) -> Result<Self::Value, E>
|
|
|
|
|
{
|
|
|
|
|
FormattedString::<F>::new(s).map_err(|x| E::custom(x.into()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'de, F: FormatSpec + ?Sized> de::Deserialize<'de> for FormattedString<F> {
|
|
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
|
|
|
where
|
|
|
|
|
D: de::Deserializer<'de>,
|
|
|
|
|
{
|
|
|
|
|
let vis = FormattedStringVisitor::<F>(PhantomData);
|
|
|
|
|
deserializer.deserialize_string(vis)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
impl<F: FormatSpec + ?Sized> FormattedStr<F>
|
|
|
|
|
{
|
|
|
|
|
/// Create a new instance without validating the input.
|
|
|
|
@ -243,7 +303,7 @@ pub mod formats
|
|
|
|
|
{
|
|
|
|
|
type Error = PEMFormatError;
|
|
|
|
|
fn validate(_s: &str) -> Result<(), Self::Error> {
|
|
|
|
|
todo!()
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|