capped string type with Deserialize impl
This commit is contained in:
1 parent
c5efe98a6c
commit
03d5baced8
4 files changed
+112
-3
No files matched your search
@@ -12,13 +12,16 @@ keywords = ["enum", "derive", "serde"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
enumscribe_derive = { version = "0.3.0", path = "../enumscribe_derive", default-features = false, optional = true }
|
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]
|
[dev-dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std", "derive", "derive_serde"]
|
# default = ["std", "derive", "derive_serde"]
|
||||||
|
default = ["derive", "derive_serde"]
|
||||||
std = ["enumscribe_derive/std"]
|
std = ["enumscribe_derive/std"]
|
||||||
derive = ["enumscribe_derive"]
|
derive = ["enumscribe_derive"]
|
||||||
derive_serde = ["derive", "enumscribe_derive/serde"]
|
derive_serde = ["derive", "serde", "enumscribe_derive/serde"]
|
||||||
|
serde = ["derive_serde", "dep:serde"]
|
||||||
@@ -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<const N: usize> {
|
||||||
|
/// The string data. It is an invariant that this must always be valid UTF-8.
|
||||||
|
buf: [u8; N],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> CappedString<N> {
|
||||||
|
/// TODO: documentation
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(s: &str) -> Option<Self> {
|
||||||
|
unsafe { Self::from_utf8_unchecked(s.as_bytes()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO: documentation
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub unsafe fn from_utf8_unchecked(bs: &[u8]) -> Option<Self> {
|
||||||
|
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<const M: usize>(&self) -> Option<CappedString<M>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Deref for CappedString<N> {
|
||||||
|
type Target = str;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> AsRef<str> for CappedString<N> {
|
||||||
|
#[inline]
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Borrow<str> for CappedString<N> {
|
||||||
|
#[inline]
|
||||||
|
fn borrow(&self) -> &str {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
impl<'de, const N: usize> serde::Deserialize<'de> for CappedString<N> {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>
|
||||||
|
{
|
||||||
|
deserializer.deserialize_str(CappedStringVisitor::<N>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CappedStringVisitor<const N: usize>;
|
||||||
|
|
||||||
|
impl<'de, const N: usize> serde::de::Visitor<'de> for CappedStringVisitor<N> {
|
||||||
|
type Value = CappedString<N>;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "a string up to {} bytes long", N)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
CappedString::new(v)
|
||||||
|
.ok_or_else(|| E::invalid_length(v.len(), &self))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||||
|
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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
//! Utilities for use by code generated by `enumscribe_derive`.
|
||||||
|
|
||||||
|
pub mod capped_string;
|
||||||
@@ -183,7 +183,8 @@
|
|||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
#[macro_use]
|
pub mod internal;
|
||||||
|
|
||||||
extern crate enumscribe_derive;
|
extern crate enumscribe_derive;
|
||||||
|
|
||||||
pub use enumscribe_derive::*;
|
pub use enumscribe_derive::*;
|
||||||
|
|||||||
Reference in new issue
Block a user