1use crate::consts::RESERVED_NOT_EMITTED_V01;
4use crate::envelope;
5use crate::error::{Error, Result};
6use crate::payload::Payload;
7use crate::tag::Tag;
8
9pub fn encode(tag: Tag, payload: &Payload) -> Result<String> {
17 if RESERVED_NOT_EMITTED_V01.contains(tag.as_bytes()) {
19 return Err(Error::ReservedTagNotEmittedInV01 {
20 got: *tag.as_bytes(),
21 });
22 }
23 if tag != payload.kind().single_tag() {
28 return Err(Error::TagKindMismatch {
29 tag: *tag.as_bytes(),
30 prefix: crate::envelope::prefix_of(payload),
31 });
32 }
33 payload.validate()?;
35 let c = envelope::package(tag, payload)?;
37 Ok(c.to_string())
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use crate::consts::VALID_STR_LENGTHS;
44
45 #[test]
46 fn encode_entr_all_lengths_succeed() {
47 for (i, len) in [16usize, 20, 24, 28, 32].iter().enumerate() {
48 let p = Payload::Entr(vec![0xAAu8; *len]);
49 let s = encode(Tag::ENTR, &p).unwrap();
50 assert_eq!(s.len(), VALID_STR_LENGTHS[i]);
51 assert!(s.starts_with("ms10entrs"), "got {}", s);
52 }
53 }
54
55 #[test]
56 fn encode_rejects_seed_tag() {
57 let p = Payload::Entr(vec![0u8; 16]);
58 let seed_tag = Tag::try_new("seed").unwrap();
59 assert!(matches!(
60 encode(seed_tag, &p),
61 Err(Error::ReservedTagNotEmittedInV01 { .. })
62 ));
63 }
64
65 #[test]
66 fn encode_rejects_xprv_tag() {
67 let p = Payload::Entr(vec![0u8; 16]);
68 let xprv_tag = Tag::try_new("xprv").unwrap();
69 assert!(matches!(
70 encode(xprv_tag, &p),
71 Err(Error::ReservedTagNotEmittedInV01 { .. })
72 ));
73 }
74
75 #[test]
76 fn encode_rejects_off_by_one_entr_length() {
77 let p = Payload::Entr(vec![0u8; 17]);
78 assert!(matches!(
79 encode(Tag::ENTR, &p),
80 Err(Error::PayloadLengthMismatch { .. })
81 ));
82 }
83}