1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use std::collections::HashMap;
use std::cmp::{Eq, Ord, Ordering, PartialEq};
use std::fmt;
use std::hash::{Hash, Hasher};

use serde::{Serialize, Serializer};
use serde_json::Value;

pub const META_PREFIX: &str = ".. ";
pub const META_SUFFIX: &str = "::";

pub enum Key {
    // site
    Name,
    Url,

    // auto
    Slug,

    // article
    Date,
    Lang,
    Title,
    Description,
    Content,

    Unknown,
}

impl Serialize for Key {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer {
        serializer.serialize_str(&self.to_string())
    }
}

impl PartialEq for Key {
    fn eq(&self, other: &Self) -> bool {
        self.to_string() == other.to_string()
    }
}

impl Eq for Key {}

impl PartialOrd for Key {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Key {
    fn cmp(&self, other: &Self) -> Ordering {
        self.to_string().cmp(&other.to_string())
    }
}

impl fmt::Display for Key {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Self::Name => write!(f, "name"),
            Self::Url => write!(f, "url"),

            Self::Slug => write!(f, "slug"),

            Self::Date => write!(f, "date"),
            Self::Description => write!(f, "description"),
            Self::Lang => write!(f, "lang"),
            Self::Title => write!(f, "title"),

            Self::Content => write!(f, "content"),

            _ => write!(f, "unknown"),
        }
    }
}

impl From<&String> for Key {
    fn from(s: &String) -> Self {
        match s.to_ascii_lowercase().as_ref() {
            "name" => Self::Name,
            "url" => Self::Url,

            "slug" => Self::Slug,

            "date" => Self::Date,
            "description" => Self::Description,
            "lang" => Self::Lang,
            "title" => Self::Title,

            "content" => Self::Content,

            _ => Self::Unknown,
        }
    }
}

impl Hash for Key {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.to_string().hash(state);
    }
}

#[derive(Serialize)]
pub struct Metadata {
    pub map: HashMap<Key, String>,
}

impl Default for Metadata {
    fn default() -> Self {
        let map: HashMap<Key, String> = HashMap::new();
        Metadata { map }
    }
}

impl Metadata {
    pub fn new() -> Self {
        Metadata::default()
    }

    pub fn add(&mut self, key: Key, value: String) -> Option<String> {
        self.map.insert(key, value)
    }

    pub fn get(&self, key: Key) -> Option<String> {
        self.map.get(&key).map(|v| v.to_owned())
    }

    pub fn has(&self, key: Key) -> bool {
        self.map.get(&key).is_some()
    }

    pub fn to_json(&self) -> Value {
        json!(self.map)
    }
}