From 03d5baced87952a7091572ff09329b970eb9aed3 Mon Sep 17 00:00:00 2001 From: pantonshire Date: Sun, 17 Sep 2023 09:52:44 +0100 Subject: [PATCH] capped string type with Deserialize impl --- enumscribe/Cargo.toml | 7 +- enumscribe/src/internal/capped_string.rs | 102 +++++++++++++++++++++++ enumscribe/src/internal/mod.rs | 3 + enumscribe/src/lib.rs | 3 +- 4 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 enumscribe/src/internal/capped_string.rs create mode 100644 enumscribe/src/internal/mod.rs diff --git a/enumscribe/Cargo.toml b/enumscribe/Cargo.toml index 9c2378f..faddb11 100644 --- a/enumscribe/Cargo.toml +++ b/enumscribe/Cargo.toml @@ -12,13 +12,16 @@ keywords = ["enum", "derive", "serde"] [dependencies] enumscribe_derive = { version = "0.3.0", path = "../enumscribe_derive", default-features = false, optional = true } +serde = { version = "1.0", default-features = false, optional = true } [dev-dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" [features] -default = ["std", "derive", "derive_serde"] +# default = ["std", "derive", "derive_serde"] +default = ["derive", "derive_serde"] std = ["enumscribe_derive/std"] derive = ["enumscribe_derive"] -derive_serde = ["derive", "enumscribe_derive/serde"] +derive_serde = ["derive", "serde", "enumscribe_derive/serde"] +serde = ["derive_serde", "dep:serde"] diff --git a/enumscribe/src/internal/capped_string.rs b/enumscribe/src/internal/capped_string.rs new file mode 100644 index 0000000..0f4a165 --- /dev/null +++ b/enumscribe/src/internal/capped_string.rs @@ -0,0 +1,102 @@ +//! Module for the [`CappedString`](CappedString) type, which is a string type which always stores +//! its data inline. + +use core::{str, convert::TryFrom, ops::Deref, borrow::Borrow, fmt}; + +/// TODO: documentation +pub struct CappedString { + /// The string data. It is an invariant that this must always be valid UTF-8. + buf: [u8; N], +} + +impl CappedString { + /// TODO: documentation + #[inline] + #[must_use] + pub fn new(s: &str) -> Option { + unsafe { Self::from_utf8_unchecked(s.as_bytes()) } + } + + /// TODO: documentation + #[inline] + #[must_use] + pub unsafe fn from_utf8_unchecked(bs: &[u8]) -> Option { + let buf = <[u8; N]>::try_from(bs).ok()?; + Some(Self { buf }) + } + + /// TODO: documentation + #[inline] + #[must_use] + pub fn as_str(&self) -> &str { + unsafe { str::from_utf8_unchecked(&self.buf) } + } + + /// TODO: documentation + #[inline] + #[must_use] + pub fn to_uppercase(&self) -> Option> { + todo!() + } +} + +impl Deref for CappedString { + type Target = str; + + #[inline] + fn deref(&self) -> &Self::Target { + self.as_str() + } +} + +impl AsRef for CappedString { + #[inline] + fn as_ref(&self) -> &str { + self + } +} + +impl Borrow for CappedString { + #[inline] + fn borrow(&self) -> &str { + self + } +} + +#[cfg(feature = "serde")] +impl<'de, const N: usize> serde::Deserialize<'de> for CappedString { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de> + { + deserializer.deserialize_str(CappedStringVisitor::) + } +} + +struct CappedStringVisitor; + +impl<'de, const N: usize> serde::de::Visitor<'de> for CappedStringVisitor { + type Value = CappedString; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "a string up to {} bytes long", N) + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + CappedString::new(v) + .ok_or_else(|| E::invalid_length(v.len(), &self)) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: serde::de::Error, + { + str::from_utf8(v) + .map_err(|_| E::invalid_value(serde::de::Unexpected::Bytes(v), &self)) + .and_then(|v| CappedString::new(v) + .ok_or_else(|| E::invalid_length(v.len(), &self))) + } +} diff --git a/enumscribe/src/internal/mod.rs b/enumscribe/src/internal/mod.rs new file mode 100644 index 0000000..6a46570 --- /dev/null +++ b/enumscribe/src/internal/mod.rs @@ -0,0 +1,3 @@ +//! Utilities for use by code generated by `enumscribe_derive`. + +pub mod capped_string; diff --git a/enumscribe/src/lib.rs b/enumscribe/src/lib.rs index 438b39b..cfc4bf7 100644 --- a/enumscribe/src/lib.rs +++ b/enumscribe/src/lib.rs @@ -183,7 +183,8 @@ #![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -#[macro_use] +pub mod internal; + extern crate enumscribe_derive; pub use enumscribe_derive::*;