use core::slice; use std::fmt::{Debug, Display}; use std::ops::Deref; use serde::{Deserialize, Serialize}; use smartstring::{LazyCompact, SmartString}; #[derive(Debug, Clone, Deserialize)] #[serde(untagged)] pub enum OneOrMany { One(T), Many(Vec), } impl OneOrMany { pub fn to_vec(self) -> Vec { match self { Self::One(x) => vec![x], Self::Many(x) => x, } } pub fn as_slice(&self) -> &[T] { match self { Self::One(x) => slice::from_ref(&x), Self::Many(x) => &x[..], } } } // // MARK: Label // /// A sanitized [String], guaranteed to only contain /// chars in `A-z`, `0-9`, and `-_`. /// /// Used for names of datasets, fields, etc. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[serde(try_from = "String", into = "String")] pub struct Label(SmartString); impl Label { pub const VALID_CHARS: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; pub fn new(str: impl Into) -> Option { let str: String = str.into(); for c in str.chars() { if !Self::VALID_CHARS.contains(c) { return None; } } return Some(Self(str.into())); } pub fn as_str(&self) -> &str { &self.0 } pub fn into_string(self) -> String { self.0.into() } } impl Display for Label { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } impl From