json_gettext/key_string/
json_get_text_builder.rs

1use std::{collections::HashMap, fs::File, path::Path};
2
3use serde::Serialize;
4use serde_json::{Map, Value};
5
6use super::{Context, JSONGetText, JSONGetTextValue};
7use crate::JSONGetTextBuildError;
8
9/// To build a JSONGetText instance, this struct can help you do that step by step.
10#[derive(Debug, Clone)]
11pub struct JSONGetTextBuilder<'a> {
12    default_key: String,
13    context:     Context<'a>,
14}
15
16impl<'a> JSONGetTextBuilder<'a> {
17    /// Create a new `JSONGetTextBuilder` instance. You need to decide your default key at the stage.
18    #[inline]
19    pub fn new<S: Into<String>>(default_key: S) -> JSONGetTextBuilder<'a> {
20        JSONGetTextBuilder {
21            default_key: default_key.into(), context: HashMap::new()
22        }
23    }
24
25    /// Add a JSON string to the context for a specify key. The JSON string must represent a map object (key-value).
26    pub fn add_json<K: AsRef<str> + Into<String>, J: AsRef<str> + ?Sized>(
27        &mut self,
28        key: K,
29        json: &'a J,
30    ) -> Result<&mut Self, JSONGetTextBuildError> {
31        if self.context.contains_key(key.as_ref()) {
32            return Err(JSONGetTextBuildError::DuplicatedKey(key.into().into()));
33        }
34
35        let map: HashMap<String, JSONGetTextValue<'a>> = serde_json::from_str(json.as_ref())?;
36
37        self.context.insert(key.into().into(), map);
38
39        Ok(self)
40    }
41
42    /// Add a JSON string to the context for a specify key. The JSON string must represent a map object (key-value).
43    pub fn add_json_owned<K: AsRef<str> + Into<String>, J: AsRef<str>>(
44        &mut self,
45        key: K,
46        json: J,
47    ) -> Result<&mut Self, JSONGetTextBuildError> {
48        if self.context.contains_key(key.as_ref()) {
49            return Err(JSONGetTextBuildError::DuplicatedKey(key.into().into()));
50        }
51
52        let value: Map<String, Value> = serde_json::from_str(json.as_ref())?;
53
54        let mut map: HashMap<String, JSONGetTextValue<'static>> =
55            HashMap::with_capacity(value.len());
56
57        for (k, v) in value {
58            map.insert(k, JSONGetTextValue::from_json_value(v));
59        }
60
61        self.context.insert(key.into().into(), map);
62
63        Ok(self)
64    }
65
66    /// Add a JSON file to the context for a specify key. The JSON file must represent a map object (key-value).
67    pub fn add_json_file<K: AsRef<str> + Into<String>, P: AsRef<Path>>(
68        &mut self,
69        key: K,
70        path: P,
71    ) -> Result<&mut Self, JSONGetTextBuildError> {
72        if self.context.contains_key(key.as_ref()) {
73            return Err(JSONGetTextBuildError::DuplicatedKey(key.into().into()));
74        }
75
76        let path = path.as_ref();
77
78        let value: Map<String, Value> = serde_json::from_reader(File::open(path)?)?;
79
80        let mut map: HashMap<String, JSONGetTextValue<'static>> =
81            HashMap::with_capacity(value.len());
82
83        for (k, v) in value {
84            map.insert(k, JSONGetTextValue::from_json_value(v));
85        }
86
87        self.context.insert(key.into().into(), map);
88
89        Ok(self)
90    }
91
92    /// Add any serializable value to the context for a specify key. The value must represent a map object (key-value).
93    pub fn add_serialize<K: AsRef<str> + Into<String>, S: Serialize>(
94        &mut self,
95        key: K,
96        value: S,
97    ) -> Result<&mut Self, JSONGetTextBuildError> {
98        if self.context.contains_key(key.as_ref()) {
99            return Err(JSONGetTextBuildError::DuplicatedKey(key.into().into()));
100        }
101
102        let value: Value = serde_json::to_value(value)?;
103
104        match value {
105            Value::Object(value) => {
106                let mut map: HashMap<String, JSONGetTextValue<'static>> =
107                    HashMap::with_capacity(value.len());
108
109                for (k, v) in value {
110                    map.insert(k, JSONGetTextValue::from_json_value(v));
111                }
112
113                self.context.insert(key.into().into(), map);
114
115                Ok(self)
116            },
117            _ => {
118                serde_json::from_str::<Map<String, Value>>("\"MagicLen\"")?;
119
120                unreachable!()
121            },
122        }
123    }
124
125    /// Add a map to the context.
126    pub fn add_map<K: AsRef<str> + Into<String>>(
127        &mut self,
128        key: K,
129        map: HashMap<String, JSONGetTextValue<'a>>,
130    ) -> Result<&mut Self, JSONGetTextBuildError> {
131        if self.context.contains_key(key.as_ref()) {
132            return Err(JSONGetTextBuildError::DuplicatedKey(key.into().into()));
133        }
134
135        self.context.insert(key.into().into(), map);
136
137        Ok(self)
138    }
139
140    /// Build a `JSONGetText` instance.
141    pub fn build(self) -> Result<JSONGetText<'a>, JSONGetTextBuildError> {
142        JSONGetText::from_context_with_default_key(self.default_key, self.context)
143    }
144}
145
146impl<'a> From<String> for JSONGetTextBuilder<'a> {
147    #[inline]
148    fn from(v: String) -> JSONGetTextBuilder<'a> {
149        JSONGetTextBuilder::new(v)
150    }
151}