mas_i18n/sprintf/
argument.rs

1// Copyright 2024 New Vector Ltd.
2// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
3//
4// SPDX-License-Identifier: AGPL-3.0-only
5// Please see LICENSE in the repository root for full details.
6
7use std::collections::HashMap;
8
9use serde_json::Value;
10
11/// A list of arguments that can be accessed by index or name.
12#[derive(Debug, Clone, Default)]
13pub struct List {
14    arguments: Vec<Value>,
15    name_index: HashMap<String, usize>,
16}
17
18impl List {
19    /// Get an argument by its index.
20    #[must_use]
21    pub fn get_by_index(&self, index: usize) -> Option<&Value> {
22        self.arguments.get(index)
23    }
24
25    /// Get an argument by its name.
26    #[must_use]
27    pub fn get_by_name(&self, name: &str) -> Option<&Value> {
28        self.name_index
29            .get(name)
30            .and_then(|index| self.get_by_index(*index))
31    }
32}
33
34impl<A: Into<Argument>> FromIterator<A> for List {
35    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
36        let mut arguments = Vec::new();
37        let mut name_index = HashMap::new();
38
39        for (index, argument) in iter.into_iter().enumerate() {
40            let argument = argument.into();
41            if let Some(name) = argument.name {
42                name_index.insert(name.clone(), index);
43            }
44
45            arguments.push(argument.value);
46        }
47
48        Self {
49            arguments,
50            name_index,
51        }
52    }
53}
54
55/// A single argument value.
56pub struct Argument {
57    name: Option<String>,
58    value: Value,
59}
60
61impl From<Value> for Argument {
62    fn from(value: Value) -> Self {
63        Self { name: None, value }
64    }
65}
66
67impl From<(&str, Value)> for Argument {
68    fn from((name, value): (&str, Value)) -> Self {
69        Self {
70            name: Some(name.to_owned()),
71            value,
72        }
73    }
74}
75
76impl From<(String, Value)> for Argument {
77    fn from((name, value): (String, Value)) -> Self {
78        Self {
79            name: Some(name),
80            value,
81        }
82    }
83}
84
85impl Argument {
86    /// Create a new argument with the given name and value.
87    #[must_use]
88    pub fn named(name: String, value: Value) -> Self {
89        Self {
90            name: Some(name),
91            value,
92        }
93    }
94
95    /// Set the name of the argument.
96    #[must_use]
97    pub fn with_name(mut self, name: String) -> Self {
98        self.name = Some(name);
99        self
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use serde_json::json;
106
107    use super::*;
108
109    #[test]
110    fn test_argument_list() {
111        let list = List::from_iter([
112            ("hello", json!("world")),
113            ("alice", json!(null)),
114            ("bob", json!(42)),
115        ]);
116
117        assert_eq!(list.get_by_index(0), Some(&json!("world")));
118        assert_eq!(list.get_by_index(1), Some(&json!(null)));
119        assert_eq!(list.get_by_index(2), Some(&json!(42)));
120        assert_eq!(list.get_by_index(3), None);
121
122        assert_eq!(list.get_by_name("hello"), Some(&json!("world")));
123        assert_eq!(list.get_by_name("alice"), Some(&json!(null)));
124        assert_eq!(list.get_by_name("bob"), Some(&json!(42)));
125        assert_eq!(list.get_by_name("charlie"), None);
126
127        let list = List::from_iter([
128            Argument::from(json!("hello")),
129            Argument::named("alice".to_owned(), json!(null)),
130            Argument::named("bob".to_owned(), json!(42)),
131        ]);
132
133        assert_eq!(list.get_by_index(0), Some(&json!("hello")));
134        assert_eq!(list.get_by_index(1), Some(&json!(null)));
135        assert_eq!(list.get_by_index(2), Some(&json!(42)));
136        assert_eq!(list.get_by_index(3), None);
137
138        assert_eq!(list.get_by_name("hello"), None);
139        assert_eq!(list.get_by_name("alice"), Some(&json!(null)));
140        assert_eq!(list.get_by_name("bob"), Some(&json!(42)));
141        assert_eq!(list.get_by_name("charlie"), None);
142    }
143}