pub trait ToEString {
fn to_estring(&self) -> EString;
}
pub trait ParseFragment: Sized {
fn parse_frag(es: EString) -> crate::Result<Self>;
}
pub trait Aggregate {
type Target: ?Sized;
fn agg(self) -> Self::Target;
}
pub trait Aggregatable {
type Item;
fn items(self) -> Vec<Self::Item>;
}
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct EString(pub String);
impl std::fmt::Display for EString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl EString {
#[must_use]
#[inline]
pub fn new() -> Self {
Self(String::new())
}
#[inline]
pub fn parse<T: ParseFragment>(self) -> crate::Result<T> {
T::parse_frag(self)
}
}
impl<T> From<T> for EString
where
T: ToEString,
{
#[inline]
fn from(val: T) -> Self {
val.to_estring()
}
}
impl std::ops::Deref for EString {
type Target = String;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ParseFragment for EString {
#[inline]
fn parse_frag(es: EString) -> crate::Result<Self> {
Ok(es)
}
}
#[cfg(feature = "aggs")]
impl Aggregatable for EString {
type Item = Self;
#[inline]
fn items(self) -> Vec<Self::Item> {
vec![self]
}
}
impl ParseFragment for String {
#[inline]
fn parse_frag(es: EString) -> crate::Result<Self> {
Ok(es.0)
}
}
impl ToEString for String {
#[inline]
fn to_estring(&self) -> EString {
EString(self.clone())
}
}
#[cfg(feature = "aggs")]
impl Aggregatable for String {
type Item = Self;
#[inline]
fn items(self) -> Vec<Self::Item> {
vec![self]
}
}
impl ParseFragment for &'static str {
#[inline]
fn parse_frag(es: EString) -> crate::Result<Self> {
Ok(Box::leak(es.0.into_boxed_str()))
}
}
impl<'a> ToEString for &'a str {
#[inline]
fn to_estring(&self) -> EString {
EString((*self).to_string())
}
}
#[cfg(feature = "aggs")]
impl<'a> Aggregatable for &'a str {
type Item = Self;
#[inline]
fn items(self) -> Vec<Self::Item> {
vec![self]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_deref_to_string() {
let estr = EString::from("hello");
assert_eq!(*estr, String::from("hello"));
}
#[test]
fn should_parse_into_itself() {
let estr = EString::from("hello");
match estr.parse::<EString>() {
Ok(res) => assert_eq!(res, EString::from("hello")),
_ => unreachable!(),
}
}
#[test]
fn should_parse_into_string() {
let estr = EString::from("hello");
match estr.parse::<String>() {
Ok(res) => assert_eq!(res, String::from("hello")),
_ => unreachable!(),
}
}
}