use crate::{CustomLabeling, Labeling, MakeLabeling, NoLabeling};
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LabelPolicy {
Opaque,
EntityNameDefault,
ExternalKeyDefault,
OpaqueByDefault,
}
pub trait Label {
type Labeler: Labeling;
const POLICY: LabelPolicy = LabelPolicy::EntityNameDefault;
fn labeler() -> Self::Labeler;
}
impl Label for () {
type Labeler = NoLabeling;
const POLICY: LabelPolicy = LabelPolicy::Opaque;
fn labeler() -> Self::Labeler {
NoLabeling
}
}
impl<T: Label> Label for Option<T> {
type Labeler = <T as Label>::Labeler;
const POLICY: LabelPolicy = T::POLICY;
fn labeler() -> Self::Labeler {
<T as Label>::labeler()
}
}
impl<T: Label, E> Label for Result<T, E> {
type Labeler = <T as Label>::Labeler;
const POLICY: LabelPolicy = T::POLICY;
fn labeler() -> Self::Labeler {
<T as Label>::labeler()
}
}
impl<K: Label, V: Label> Label for HashMap<K, V> {
type Labeler = CustomLabeling;
fn labeler() -> Self::Labeler {
let k_labeler = <K as Label>::labeler();
let v_labeler = <V as Label>::labeler();
CustomLabeling::from(format!(
"HashMap<{},{}",
k_labeler.label(),
v_labeler.label()
))
}
}
macro_rules! primitive_label {
($i:ty) => {
impl Label for $i {
type Labeler = MakeLabeling<Self>;
fn labeler() -> Self::Labeler {
MakeLabeling::<Self>::default()
}
}
};
}
primitive_label!(bool);
primitive_label!(char);
primitive_label!(f32);
primitive_label!(f64);
primitive_label!(i8);
primitive_label!(i32);
primitive_label!(i64);
primitive_label!(i128);
primitive_label!(isize);
primitive_label!(u8);
primitive_label!(u16);
primitive_label!(u32);
primitive_label!(u64);
primitive_label!(u128);
primitive_label!(usize);
primitive_label!(String);
impl Label for &str {
type Labeler = MakeLabeling<Self>;
fn labeler() -> Self::Labeler {
MakeLabeling::<Self>::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_label_option_delegation() {
let opt_labeler = <Option<String> as Label>::labeler();
let str_labeler = <String as Label>::labeler();
assert_eq!(opt_labeler.label(), str_labeler.label());
}
#[test]
fn test_label_result_delegation() {
let res_labeler = <Result<u32, String> as Label>::labeler();
let u32_labeler = <u32 as Label>::labeler();
assert_eq!(res_labeler.label(), u32_labeler.label());
}
#[test]
fn test_label_hashmap_format() {
let labeler = <HashMap<String, u32> as Label>::labeler();
let label = labeler.label();
assert!(label.contains("String") || label.contains("str")); assert!(label.contains("u32"));
assert_eq!(label, "HashMap<String,u32");
}
#[test]
fn test_label_unit_impl() {
assert!(<() as Label>::labeler().label().is_empty());
assert_eq!(<() as Label>::POLICY, LabelPolicy::Opaque);
}
}