ndjsonlogger 0.1.0

ndjsonlogger
Documentation
use proc_macro::TokenTree;

#[derive(Clone, Copy)]
pub struct EntryType {
    atom_type: AtomType,
    opt: bool,
}

impl EntryType {
    pub fn new() -> Self {
        Self {
            atom_type: AtomType::String,
            opt: false,
        }
    }

    pub fn from_type(tts: &[&TokenTree]) -> Self {
        for (atom_type, type_fn) in TYPE_FNS.iter() {
            if type_fn(tts) {
                return Self {
                    atom_type: *atom_type,
                    opt: false,
                };
            }

            if type_fn_opt(tts, type_fn) {
                return Self {
                    atom_type: *atom_type,
                    opt: true,
                };
            }
        }

        panic!("unrecognised type for entry value");
    }

    pub fn is_opt(self) -> bool {
        self.opt
    }

    pub fn is_str(self) -> bool {
        self.atom_type == AtomType::String
    }

    pub fn atom_type(self) -> (&'static str, Option<&'static str>) {
        self.atom_type.atom_type()
    }
}

#[derive(Clone, Copy, PartialEq, Eq)]
enum AtomType {
    String,
    U64,
    I64,
    U32,
    I32,
    U16,
    I16,
    U8,
    I8,
    F64,
    F32,
    F16,
    Usize,
    Bool,
}

impl AtomType {
    fn atom_type(self) -> (&'static str, Option<&'static str>) {
        match self {
            AtomType::String => ("String", None),
            AtomType::U64 => ("Uint", None),
            AtomType::I64 => ("Int", None),
            AtomType::U32 => ("Uint", Some("u64")),
            AtomType::I32 => ("Int", Some("i64")),
            AtomType::U16 => ("Uint", Some("u64")),
            AtomType::I16 => ("Int", Some("i64")),
            AtomType::U8 => ("Uint", Some("u64")),
            AtomType::I8 => ("Int", Some("i64")),
            AtomType::F64 => ("Float", None),
            AtomType::F32 => ("Float", Some("f64")),
            AtomType::F16 => ("Float", Some("f64")),
            AtomType::Usize => ("Uint", Some("u64")),
            AtomType::Bool => ("Bool", None),
        }
    }
}

#[allow(clippy::type_complexity)]
const TYPE_FNS: &[(AtomType, fn(&[&TokenTree]) -> bool)] = &[
    (AtomType::String, type_fn_string),
    (AtomType::U64, type_fn_u64),
    (AtomType::I64, type_fn_i64),
    (AtomType::U32, type_fn_u32),
    (AtomType::I32, type_fn_i32),
    (AtomType::U16, type_fn_u16),
    (AtomType::I16, type_fn_i16),
    (AtomType::U8, type_fn_u8),
    (AtomType::I8, type_fn_i8),
    (AtomType::F64, type_fn_f64),
    (AtomType::F32, type_fn_f32),
    (AtomType::F16, type_fn_f16),
    (AtomType::Usize, type_fn_usize),
    (AtomType::Bool, type_fn_bool),
];

fn type_fn_string(tts: &[&TokenTree]) -> bool {
    if tts.len() != 2 {
        return false;
    }

    if let Some(TokenTree::Punct(pct)) = tts.get(0) {
        if pct.as_char() == '&' {
            if let Some(TokenTree::Ident(ident)) = tts.get(1) {
                if ident.to_string() == "str" {
                    return true;
                }
            }
        }
    }

    false
}

fn type_fn_u64(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "u64")
}

fn type_fn_i64(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "i64")
}

fn type_fn_u32(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "u32")
}

fn type_fn_i32(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "i32")
}

fn type_fn_u16(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "u16")
}

fn type_fn_i16(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "i16")
}

fn type_fn_u8(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "u8")
}

fn type_fn_i8(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "i8")
}

fn type_fn_f64(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "f64")
}

fn type_fn_f32(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "f32")
}

fn type_fn_f16(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "f16")
}

fn type_fn_usize(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "usize")
}

fn type_fn_bool(tts: &[&TokenTree]) -> bool {
    type_fn_single_ident(tts, "bool")
}

fn type_fn_single_ident(tts: &[&TokenTree], ident_str: &str) -> bool {
    if tts.len() != 1 {
        return false;
    }

    if let Some(TokenTree::Ident(ident)) = tts.get(0) {
        if ident.to_string() == ident_str {
            return true;
        }
    }

    false
}

fn type_fn_opt(tts: &[&TokenTree], inner_type_fn: &fn(&[&TokenTree]) -> bool) -> bool {
    if tts.len() < 4 {
        return false;
    }

    if let Some(TokenTree::Ident(ident)) = tts.get(0) {
        if ident.to_string() == "Option" {
            if let Some(TokenTree::Punct(pct)) = tts.get(1) {
                if pct.as_char() == '<' {
                    if let Some(TokenTree::Punct(pct)) = tts.get(tts.len() - 1) {
                        if pct.as_char() == '>' {
                            return inner_type_fn(&tts[2..(tts.len() - 1)]);
                        }
                    }
                }
            }
        }
    }

    false
}