ssh_key/certificate/
options_map.rs1use crate::{Error, Result};
4use alloc::{collections::BTreeMap, string::String, vec::Vec};
5use core::{
6 cmp::Ordering,
7 ops::{Deref, DerefMut},
8};
9use encoding::{CheckedSum, Decode, Encode, Reader, Writer};
10
11#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
13pub struct OptionsMap(pub BTreeMap<String, String>);
14
15impl OptionsMap {
16 #[must_use]
18 pub fn new() -> Self {
19 Self::default()
20 }
21}
22
23impl Deref for OptionsMap {
24 type Target = BTreeMap<String, String>;
25
26 fn deref(&self) -> &Self::Target {
27 &self.0
28 }
29}
30
31impl DerefMut for OptionsMap {
32 fn deref_mut(&mut self) -> &mut Self::Target {
33 &mut self.0
34 }
35}
36
37impl Decode for OptionsMap {
38 type Error = Error;
39
40 fn decode(reader: &mut impl Reader) -> Result<Self> {
41 reader.read_prefixed(|reader| {
42 let mut entries = Vec::<(String, String)>::new();
43
44 while !reader.is_finished() {
45 let name = String::decode(reader)?;
46 let data = reader.read_prefixed(|reader| {
47 if reader.remaining_len() > 0 {
48 String::decode(reader)
49 } else {
50 Ok(String::default())
51 }
52 })?;
53
54 if let Some((prev_name, _)) = entries.last() {
58 if prev_name.cmp(&name) != Ordering::Less {
59 return Err(Error::FormatEncoding);
60 }
61 }
62
63 entries.push((name, data));
64 }
65
66 Ok(OptionsMap::from_iter(entries))
67 })
68 }
69}
70
71impl Encode for OptionsMap {
72 fn encoded_len(&self) -> encoding::Result<usize> {
73 self.iter().try_fold(4, |acc, (name, data)| {
74 [
75 acc,
76 name.encoded_len()?,
77 if data.is_empty() {
78 4
79 } else {
80 data.encoded_len_prefixed()?
81 },
82 ]
83 .checked_sum()
84 })
85 }
86
87 fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
88 self.encoded_len()?
89 .checked_sub(4)
90 .ok_or(encoding::Error::Length)?
91 .encode(writer)?;
92
93 for (name, data) in self.iter() {
94 name.encode(writer)?;
95 if data.is_empty() {
96 0usize.encode(writer)?;
97 } else {
98 data.encode_prefixed(writer)?;
99 }
100 }
101
102 Ok(())
103 }
104}
105
106impl From<BTreeMap<String, String>> for OptionsMap {
107 fn from(map: BTreeMap<String, String>) -> OptionsMap {
108 OptionsMap(map)
109 }
110}
111
112impl From<OptionsMap> for BTreeMap<String, String> {
113 fn from(map: OptionsMap) -> BTreeMap<String, String> {
114 map.0
115 }
116}
117
118impl FromIterator<(String, String)> for OptionsMap {
119 fn from_iter<T>(iter: T) -> Self
120 where
121 T: IntoIterator<Item = (String, String)>,
122 {
123 BTreeMap::from_iter(iter).into()
124 }
125}