serde_cqcode/data/
mod.rs

1pub(crate) mod model;
2
3use std::{
4    collections::HashMap,
5    num::{ParseFloatError, ParseIntError},
6};
7
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd)]
11#[serde(untagged)]
12pub enum Number {
13    Int(i64),
14    Float(f64),
15}
16
17#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
18#[serde(untagged)]
19pub enum CodeValue {
20    Bool(bool),
21    String(String),
22    Number(Number),
23    CQCode(CQCode),
24}
25
26#[derive(Debug, thiserror::Error)]
27pub enum NumberError {
28    #[error(transparent)]
29    ParseInt(#[from] ParseIntError),
30    #[error(transparent)]
31    ParseFloat(#[from] ParseFloatError),
32}
33
34impl Number {
35    pub fn parse(s: impl AsRef<str>) -> Result<Self, NumberError> {
36        let s = s.as_ref();
37        if s.contains('.') {
38            s.parse::<f64>()
39                .map(Number::Float)
40                .map_err(NumberError::from)
41        } else {
42            s.parse::<i64>().map(Number::Int).map_err(NumberError::from)
43        }
44    }
45}
46
47/// Represents a CQCode, which is a structured data type used for encoding
48/// and decoding messages with a specific type and associated data.
49/// 
50/// # Fields
51/// 
52/// * `cq_type` - A string representing the type of the CQCode.
53/// * `data` - A `HashMap` containing key-value pairs of additional data
54///   associated with the CQCode.
55#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
56pub struct CQCode {
57    #[serde(rename = "$type")]
58    pub cq_type: String,
59    #[serde(flatten)]
60    pub data: HashMap<String, String>,
61}
62
63impl CQCode {
64    pub fn new(ty: impl Into<String>) -> Self {
65        CQCode {
66            cq_type: ty.into(),
67            data: HashMap::default(),
68        }
69    }
70
71    pub fn data_mut(&mut self) -> &mut HashMap<String, String> {
72        &mut self.data
73    }
74
75    pub fn data(&self) -> &HashMap<String, String> {
76        &self.data
77    }
78}
79
80impl<T, V, VS> From<(T, V)> for CQCode
81where
82    V: IntoIterator<Item = (VS, VS)>,
83    T: Into<String>,
84    VS: Into<String>,
85{
86    fn from(value: (T, V)) -> Self {
87        let (ty, data) = value;
88        let mut cq_code = CQCode::new(ty.into());
89        for (key, value) in data {
90            cq_code.data.insert(key.into(), value.into());
91        }
92        cq_code
93    }
94}
95
96pub fn parse_code(code: &str) -> Option<char> {
97    match code {
98        "amp" => Some('&'),
99        "#91" => Some('['),
100        "#93" => Some(']'),
101        "#44" => Some(','),
102        _ => None,
103    }
104}
105
106pub const fn escape_char(code: char) -> Option<&'static str> {
107    match code {
108        '&' => Some("amp"),
109        '[' => Some("#91"),
110        ']' => Some("#93"),
111        ',' => Some("#44"),
112        _ => None,
113    }
114}
115
116pub fn escape_str(s: &str) -> String {
117    let mut out = String::new();
118    for ele in s.chars() {
119        if let Some(escaped) = escape_char(ele) {
120            out.push_str(escaped);
121        } else {
122            out.push(ele);
123        }
124    }
125
126    out
127}