coven_format/
code_fields.rs1use crate::error::{bound, Error};
7use crate::wire::{get_text, Decoder, Wire};
8use coven_crypto::{SecretBytes, SecretText};
9use zeroize::Zeroizing;
10
11pub const MAX_STORAGE: usize = 16 * 1024;
13
14pub struct FieldWriter {
18 bytes: Option<Zeroizing<Vec<u8>>>,
19 len: usize,
20}
21
22impl FieldWriter {
23 fn write(&mut self, part: &[u8]) -> Result<(), Error> {
24 self.len = self.len.saturating_add(part.len());
25 bound(self.len, MAX_STORAGE, "storage settings")?;
26 if let Some(bytes) = &mut self.bytes {
27 bytes.extend_from_slice(part);
28 }
29 Ok(())
30 }
31
32 pub fn u8(&mut self, value: u8) -> Result<(), Error> {
34 self.write(&[value])
35 }
36
37 pub fn u16(&mut self, value: u16) -> Result<(), Error> {
39 self.write(&value.to_be_bytes())
40 }
41
42 pub fn text(&mut self, value: &str) -> Result<(), Error> {
44 bound(value.len(), MAX_STORAGE, "storage text")?;
45 self.write(&(value.len() as u32).to_be_bytes())?;
46 self.write(value.as_bytes())
47 }
48
49 pub fn option<T>(
51 &mut self,
52 value: Option<T>,
53 put: impl FnOnce(&mut Self, T) -> Result<(), Error>,
54 ) -> Result<(), Error> {
55 match value {
56 None => self.u8(0),
57 Some(value) => {
58 self.u8(1)?;
59 put(self, value)
60 }
61 }
62 }
63}
64
65pub fn pack(put: impl Fn(&mut FieldWriter) -> Result<(), Error>) -> Result<SecretBytes, Error> {
68 let mut count = FieldWriter { bytes: None, len: 0 };
69 put(&mut count)?;
70 let mut bytes = Zeroizing::new(Vec::new());
71 bytes.try_reserve_exact(count.len)?;
72 let mut writer = FieldWriter { bytes: Some(bytes), len: 0 };
73 put(&mut writer)?;
74 let mut bytes = writer.bytes.expect("the writing pass keeps its buffer");
75 assert_eq!(bytes.len(), count.len, "storage fields changed between passes");
76 Ok(SecretBytes::new(std::mem::take(&mut *bytes)))
77}
78
79pub struct FieldReader<'a>(Decoder<'a>);
83
84impl<'a> FieldReader<'a> {
85 pub fn new(bytes: &'a [u8]) -> Result<Self, Error> {
87 bound(bytes.len(), MAX_STORAGE, "storage settings")?;
88 Ok(Self(Decoder::new(bytes)?))
89 }
90
91 pub fn u8(&mut self) -> Result<u8, Error> {
93 u8::get(&mut self.0)
94 }
95
96 pub fn u16(&mut self) -> Result<u16, Error> {
98 u16::get(&mut self.0)
99 }
100
101 pub fn text(&mut self, field: &'static str) -> Result<String, Error> {
103 get_text(&mut self.0, MAX_STORAGE, field)
104 }
105
106 pub fn secret_text(&mut self, field: &'static str) -> Result<SecretText, Error> {
108 Ok(SecretText::new(self.text(field)?))
109 }
110
111 pub fn option<T, E: From<Error>>(
115 &mut self,
116 get: impl FnOnce(&mut Self) -> Result<T, E>,
117 ) -> Result<Option<T>, E> {
118 match self.u8()? {
119 0 => Ok(None),
120 1 => Ok(Some(get(self)?)),
121 tag => Err(Error::UnknownTag { field: "option", tag }.into()),
122 }
123 }
124
125 pub fn finish(self) -> Result<(), Error> {
127 self.0.finish()
128 }
129}
130
131#[cfg(test)]
132#[path = "code_fields_tests.rs"]
133mod tests;