// 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) } }