1pub(crate) mod generator;
2pub(crate) mod parser;
3
4use std::path::PathBuf;
5
6pub use esp_nvs::MAX_KEY_LENGTH;
7
8use crate::error::Error;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct NvsEntry {
13 pub namespace: String,
15 pub key: String,
17 pub content: EntryContent,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum EntryContent {
24 Data(DataValue),
26 File {
28 encoding: FileEncoding,
30 file_path: PathBuf,
32 },
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
41pub enum FileEncoding {
42 String,
44 Hex2Bin,
46 Base64,
48 Binary,
50}
51
52impl std::str::FromStr for FileEncoding {
53 type Err = Error;
54
55 fn from_str(s: &str) -> Result<Self, Self::Err> {
56 match s {
57 "string" => Ok(Self::String),
58 "hex2bin" => Ok(Self::Hex2Bin),
59 "base64" => Ok(Self::Base64),
60 "binary" => Ok(Self::Binary),
61 _ => Err(Error::InvalidEncoding(s.to_string())),
62 }
63 }
64}
65
66impl FileEncoding {
67 pub fn as_str(&self) -> &'static str {
69 match self {
70 Self::String => "string",
71 Self::Hex2Bin => "hex2bin",
72 Self::Base64 => "base64",
73 Self::Binary => "binary",
74 }
75 }
76}
77
78impl std::fmt::Display for FileEncoding {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 f.write_str(self.as_str())
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
86pub enum DataValue {
87 U8(u8),
89 I8(i8),
91 U16(u16),
93 I16(i16),
95 U32(u32),
97 I32(i32),
99 U64(u64),
101 I64(i64),
103 String(String),
105 Binary(Vec<u8>),
107}
108
109impl DataValue {
110 pub fn encoding_str(&self) -> &'static str {
116 match self {
117 Self::U8(_) => "u8",
118 Self::I8(_) => "i8",
119 Self::U16(_) => "u16",
120 Self::I16(_) => "i16",
121 Self::U32(_) => "u32",
122 Self::I32(_) => "i32",
123 Self::U64(_) => "u64",
124 Self::I64(_) => "i64",
125 Self::String(_) => "string",
126 Self::Binary(_) => "base64",
127 }
128 }
129}
130
131impl std::fmt::Display for DataValue {
132 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133 match self {
134 Self::U8(v) => write!(f, "{v}"),
135 Self::I8(v) => write!(f, "{v}"),
136 Self::U16(v) => write!(f, "{v}"),
137 Self::I16(v) => write!(f, "{v}"),
138 Self::U32(v) => write!(f, "{v}"),
139 Self::I32(v) => write!(f, "{v}"),
140 Self::U64(v) => write!(f, "{v}"),
141 Self::I64(v) => write!(f, "{v}"),
142 Self::String(s) => f.write_str(s),
143 Self::Binary(b) => {
144 use base64::Engine;
145 f.write_str(&base64::engine::general_purpose::STANDARD.encode(b))
146 }
147 }
148 }
149}
150
151impl NvsEntry {
152 pub fn new_data(namespace: String, key: String, value: DataValue) -> Self {
156 Self {
157 namespace,
158 key,
159 content: EntryContent::Data(value),
160 }
161 }
162
163 pub fn new_file(namespace: String, key: String, encoding: FileEncoding, file_path: PathBuf) -> Self {
168 Self {
169 namespace,
170 key,
171 content: EntryContent::File { encoding, file_path },
172 }
173 }
174
175 pub fn set_content(&mut self, content: EntryContent) {
177 self.content = content;
178 }
179
180 pub fn set_data(&mut self, value: DataValue) {
184 self.content = EntryContent::Data(value);
185 }
186
187 pub fn set_file(&mut self, encoding: FileEncoding, file_path: PathBuf) {
191 self.content = EntryContent::File { encoding, file_path };
192 }
193}
194
195pub(crate) fn validate_key(key: &str) -> Result<(), Error> {
197 if key.is_empty() {
198 return Err(Error::InvalidKey("key must not be empty".to_string()));
199 }
200 if key.len() > MAX_KEY_LENGTH {
201 return Err(Error::InvalidKey(format!(
202 "key '{}' is too long (max {} characters)",
203 key, MAX_KEY_LENGTH
204 )));
205 }
206 Ok(())
207}