From d2f423521ec76406944ad83098ec33afe20c692b Mon Sep 17 00:00:00 2001 From: Kim Altintop Date: Mon, 9 Jan 2023 13:18:33 +0100 Subject: This is it Squashed commit of all the exploration history. Development starts here. Signed-off-by: Kim Altintop --- src/str.rs | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/str.rs (limited to 'src/str.rs') diff --git a/src/str.rs b/src/str.rs new file mode 100644 index 0000000..1825e06 --- /dev/null +++ b/src/str.rs @@ -0,0 +1,94 @@ +// Copyright © 2022 Kim Altintop +// SPDX-License-Identifier: GPL-2.0-only WITH openvpn-openssl-exception + +use core::fmt; +use std::{ + ops::Deref, + str::FromStr, +}; + +use anyhow::ensure; + +// A variable-length string type with a maximum length `N`. +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Serialize)] +pub struct Varchar(T); + +impl Varchar +where + T: AsRef, +{ + pub fn len(&self) -> usize { + self.0.as_ref().len() + } + + pub fn is_empty(&self) -> bool { + self.0.as_ref().is_empty() + } + + fn try_from_t(t: T) -> crate::Result { + let len = t.as_ref().len(); + ensure!(len <= N, "string length exceeds {N}: {len}"); + Ok(Self(t)) + } +} + +impl Varchar { + pub const fn new() -> Self { + Self(String::new()) + } +} + +impl TryFrom for Varchar { + type Error = crate::Error; + + fn try_from(s: String) -> Result { + Self::try_from_t(s) + } +} + +impl FromStr for Varchar { + type Err = crate::Error; + + fn from_str(s: &str) -> Result { + Self::try_from(s.to_owned()) + } +} + +impl<'a, const N: usize> TryFrom<&'a str> for Varchar<&'a str, N> { + type Error = crate::Error; + + fn try_from(s: &'a str) -> Result { + Self::try_from_t(s) + } +} + +impl Deref for Varchar { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl fmt::Display for Varchar +where + T: AsRef, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.0.as_ref()) + } +} + +impl<'de, T, const N: usize> serde::Deserialize<'de> for Varchar +where + T: serde::Deserialize<'de> + TryInto, + >::Error: fmt::Display, +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let t = T::deserialize(deserializer)?; + t.try_into().map_err(serde::de::Error::custom) + } +} -- cgit v1.2.3