hard formatted strings also validate during serde deserialisation

new-idea
Avril 4 years ago
parent 80bd992e72
commit 055039d2e0
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -3,3 +3,7 @@
pub const ANON_NAME: &'static str = "名無し";
/// Max length of `name` and `email` feilds in posts.
pub const POST_ID_MAX_LEN: usize = 32;
/// The salt to use for tripcode hashes
pub const TRIPCODE_SALT: khash::salt::Salt = khash::salt::Salt::internal();
/// The tripcode algorithm to use
pub const TRIPCODE_ALGO: khash::ctx::Algorithm = khash::ctx::Algorithm::Sha256;

@ -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(())
}
}

@ -88,5 +88,6 @@ mod tests
println!("Post json: {:?}", post_json);
let post2: super::Post = serde_json::from_slice(&post_json[..]).expect("Deserialise");
assert_eq!(post, post2);
println!("Post was: {:?}", post);
}
}

@ -1,14 +1,15 @@
use super::*;
use khash::ctx::{self, Context};
use khash::salt::Salt;
use khash::ctx::Context;
//use khash::salt::Salt;
use std::fmt;
/// A newtype tripcode string
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Tripcode(String);
lazy_static!{
static ref CONTEXT: Context = Context::new(ctx::Algorithm::Sha256Truncated, Salt::internal());
static ref CONTEXT: Context = Context::new(defaults::TRIPCODE_ALGO, defaults::TRIPCODE_SALT);
}
impl Tripcode

Loading…
Cancel
Save