satex-core 0.1.2

Satex核心库,提供基础和通用的一些功能。
Documentation
use std::str::Split;

use serde::de::DeserializeOwned;
use serde_yaml::{Mapping, Value};

use crate::{satex_error, Error};

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum GatherMode {
    Default,
    Tail,
    TailSequence,
    Sequence,
    SequenceFlag,
    Unsupported,
}

#[derive(Clone, Copy)]
pub struct Shortcut<'a>(Option<&'a str>);

impl<'a> From<&'a str> for Shortcut<'a> {
    fn from(value: &'a str) -> Self {
        Shortcut(Some(value))
    }
}

impl<'a> Shortcut<'a> {
    pub fn none() -> Self {
        Self(None)
    }

    pub fn iter(&self) -> Iter {
        Iter(self.0.map(|v| v.split(',')))
    }

    pub fn deserialize<T: DeserializeOwned>(
        &self,
        fields: &[&'static str],
        mode: GatherMode,
    ) -> Result<T, Error> {
        let len = fields.len();
        let mut mapping = Mapping::new();
        let mut values = self.into_iter().collect::<Vec<_>>();
        match mode {
            GatherMode::Default => {
                for index in 0..len {
                    if let Some(value) = values.get(index) {
                        mapping.insert(Value::from(fields[index]), Value::from(*value));
                    }
                }
            }
            GatherMode::Tail | GatherMode::TailSequence => {
                if values.len() > fields.len() {
                    for index in 0..len {
                        let key = Value::from(fields[index]);
                        let value = if index == len - 1 {
                            if GatherMode::Tail == mode {
                                Value::from(values.join(","))
                            } else {
                                Value::from(vec![Value::from(values.join(","))])
                            }
                        } else {
                            Value::from(values.remove(index))
                        };
                        mapping.insert(key, value);
                    }
                } else {
                    return self.deserialize(fields, GatherMode::Default);
                }
            }
            GatherMode::Sequence => {
                if len != 1 {
                    return Err(satex_error!(
                        "Shortcut gather mode `GatherList` must have fields of size 1!"
                    ));
                }
                mapping.insert(Value::from(fields[0]), Value::from(values));
            }
            GatherMode::SequenceFlag => {
                if len != 2 {
                    return Err(satex_error!(
                        "Shortcut gather mode `GatherListTailFlag` must have fields of size 2!"
                    ));
                }
                if !values.is_empty() {
                    let last = values.remove(values.len() - 1);
                    if let Some(flag) = last.parse::<bool>().ok() {
                        mapping.insert(Value::from(fields[1]), Value::from(flag));
                    } else {
                        values.push(last);
                    }
                    mapping.insert(Value::from(fields[0]), Value::from(values));
                }
            }
            GatherMode::Unsupported => return Err(satex_error!("Shortcut not supported!")),
        };
        serde_yaml::from_value(Value::Mapping(mapping)).map_err(|e| satex_error!(e))
    }
}

impl<'a> IntoIterator for Shortcut<'a> {
    type Item = &'a str;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        Iter(self.0.map(|v| v.split(',')))
    }
}

pub struct Iter<'a>(Option<Split<'a, char>>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        match &mut self.0 {
            None => None,
            Some(split) => split.next().map(|item| item.trim()),
        }
    }
}