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, PartialEq, PartialOrd, Ord)]
13pub struct OptionsMap(pub BTreeMap<String, String>);
14
15impl OptionsMap {
16 pub fn new() -> Self {
18 Self::default()
19 }
20}
21
22impl Deref for OptionsMap {
23 type Target = BTreeMap<String, String>;
24
25 fn deref(&self) -> &Self::Target {
26 &self.0
27 }
28}
29
30impl DerefMut for OptionsMap {
31 fn deref_mut(&mut self) -> &mut Self::Target {
32 &mut self.0
33 }
34}
35
36impl Decode for OptionsMap {
37 type Error = Error;
38
39 fn decode(reader: &mut impl Reader) -> Result<Self> {
40 reader.read_prefixed(|reader| {
41 let mut entries = Vec::<(String, String)>::new();
42
43 while !reader.is_finished() {
44 let name = String::decode(reader)?;
45 let data = reader.read_prefixed(|reader| {
46 if reader.remaining_len() > 0 {
47 String::decode(reader)
48 } else {
49 Ok(String::default())
50 }
51 })?;
52
53 if let Some((prev_name, _)) = entries.last() {
57 if prev_name.cmp(&name) != Ordering::Less {
58 return Err(Error::FormatEncoding);
59 }
60 }
61
62 entries.push((name, data));
63 }
64
65 Ok(OptionsMap::from_iter(entries))
66 })
67 }
68}
69
70impl Encode for OptionsMap {
71 fn encoded_len(&self) -> encoding::Result<usize> {
72 self.iter()
73 .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 .map_err(Into::into)
86 }
87
88 fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
89 self.encoded_len()?
90 .checked_sub(4)
91 .ok_or(encoding::Error::Length)?
92 .encode(writer)?;
93
94 for (name, data) in self.iter() {
95 name.encode(writer)?;
96 if data.is_empty() {
97 0usize.encode(writer)?;
98 } else {
99 data.encode_prefixed(writer)?
100 }
101 }
102
103 Ok(())
104 }
105}
106
107impl From<BTreeMap<String, String>> for OptionsMap {
108 fn from(map: BTreeMap<String, String>) -> OptionsMap {
109 OptionsMap(map)
110 }
111}
112
113impl From<OptionsMap> for BTreeMap<String, String> {
114 fn from(map: OptionsMap) -> BTreeMap<String, String> {
115 map.0
116 }
117}
118
119impl FromIterator<(String, String)> for OptionsMap {
120 fn from_iter<T>(iter: T) -> Self
121 where
122 T: IntoIterator<Item = (String, String)>,
123 {
124 BTreeMap::from_iter(iter).into()
125 }
126}