1use std::num::NonZeroU64;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct PictureType(u8);
7
8impl PictureType {
9 pub const ZERO: PictureType = PictureType(0);
11
12 pub fn new(v: u32) -> Option<PictureType> {
13 let b = u8::try_from(v).ok()?;
14 if b > 20 { None } else { Some(PictureType(b)) }
15 }
16
17 pub fn get(self) -> u32 {
18 u32::from(self.0)
19 }
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub struct BlobLen(NonZeroU64);
28
29impl BlobLen {
30 pub fn new(v: u64) -> Option<BlobLen> {
31 NonZeroU64::new(v).map(BlobLen)
32 }
33
34 pub fn get(self) -> u64 {
35 self.0.get()
36 }
37}
38
39#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct TagInput {
43 pub key: String,
44 pub value: String,
45}
46
47impl TagInput {
48 pub fn new(key: &str, value: &str) -> TagInput {
49 TagInput {
50 key: key.to_string(),
51 value: value.to_string(),
52 }
53 }
54}
55
56#[derive(Debug, Clone, PartialEq, Eq)]
61pub struct ArtInput {
62 pub art_id: i64,
63 pub mime: String,
64 pub description: String,
65 pub picture_type: PictureType,
66 pub width: u32,
67 pub height: u32,
68 pub data_len: BlobLen,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq)]
74pub struct EmbeddedPicture {
75 pub mime: String,
76 pub picture_type: PictureType,
77 pub description: String,
78 pub width: u32,
79 pub height: u32,
80 pub data: Vec<u8>,
81}
82
83#[derive(Debug, Clone, PartialEq, Eq)]
89pub struct BinaryTagInput {
90 pub key: String,
91 pub payload_id: i64,
92 pub len: BlobLen,
93}
94
95#[derive(Debug, Clone, PartialEq, Eq)]
100pub struct EmbeddedBinaryTag {
101 pub key: String,
102 pub payload: Vec<u8>,
103}
104
105#[cfg(test)]
106mod tests {
107 use super::{BinaryTagInput, BlobLen};
108
109 #[test]
110 fn binary_tag_input_constructs() {
111 let b = BinaryTagInput {
112 key: "PRIV".into(),
113 payload_id: 7,
114 len: BlobLen::new(3).unwrap(),
115 };
116 assert_eq!(b.payload_id, 7);
117 assert_eq!(b.len.get(), 3);
118 }
119
120 #[test]
121 fn embedded_binary_tag_constructs() {
122 let e = super::EmbeddedBinaryTag {
123 key: "PRIV".into(),
124 payload: vec![1, 2, 3],
125 };
126 assert_eq!(e.key, "PRIV");
127 assert_eq!(e.payload.len(), 3);
128 }
129
130 #[test]
131 fn picture_type_accepts_full_range() {
132 for v in 0..=20u32 {
133 assert_eq!(super::PictureType::new(v).unwrap().get(), v);
134 }
135 }
136
137 #[test]
138 fn picture_type_rejects_out_of_range() {
139 assert!(super::PictureType::new(21).is_none());
140 assert!(super::PictureType::new(u32::MAX).is_none());
141 }
142
143 #[test]
144 fn blob_len_rejects_zero() {
145 assert!(super::BlobLen::new(0).is_none());
146 }
147
148 #[test]
149 fn blob_len_round_trips_nonzero() {
150 assert_eq!(super::BlobLen::new(1).unwrap().get(), 1);
151 assert_eq!(super::BlobLen::new(u64::MAX).unwrap().get(), u64::MAX);
152 }
153}