1use crate::io::{Read, Seek};
5use crate::{BinRead, BinResult, ReadOptions};
6#[cfg(not(feature = "std"))]
7use alloc::vec::Vec;
8use core::fmt;
9
10pub struct Punctuated<T: BinRead, P: BinRead> {
32 data: Vec<T>,
33 pub seperators: Vec<P>,
34}
35
36impl<C: Copy + 'static, T: BinRead<Args = C>, P: BinRead<Args = ()>> Punctuated<T, P> {
37 pub fn separated<R: Read + Seek>(
60 reader: &mut R,
61 options: &ReadOptions,
62 args: C,
63 ) -> BinResult<Self> {
64 let count = match options.count {
65 Some(x) => x,
66 None => panic!("Missing count for Punctuated"),
67 };
68
69 let mut data = Vec::with_capacity(count);
70 let mut seperators = Vec::with_capacity(count.max(1) - 1);
71
72 for i in 0..count {
73 data.push(T::read_options(reader, &options, args)?);
74 if i + 1 != count {
75 seperators.push(P::read_options(reader, options, ())?);
76 }
77 }
78
79 Ok(Self { data, seperators })
80 }
81
82 pub fn separated_trailing<R: Read + Seek>(
86 reader: &mut R,
87 options: &ReadOptions,
88 args: C,
89 ) -> BinResult<Self> {
90 let count = match options.count {
91 Some(x) => x,
92 None => panic!("Missing count for Punctuated"),
93 };
94
95 let mut data = Vec::with_capacity(count);
96 let mut seperators = Vec::with_capacity(count);
97
98 for _ in 0..count {
99 data.push(T::read_options(reader, &options, args)?);
100 seperators.push(P::read_options(reader, options, ())?);
101 }
102
103 Ok(Self { data, seperators })
104 }
105}
106
107impl<T: BinRead + fmt::Debug, P: BinRead> fmt::Debug for Punctuated<T, P> {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 self.data.fmt(f)
110 }
111}
112
113impl<T: BinRead, P: BinRead> core::ops::Deref for Punctuated<T, P> {
114 type Target = Vec<T>;
115
116 fn deref(&self) -> &Self::Target {
117 &self.data
118 }
119}
120
121impl<T: BinRead, P: BinRead> core::ops::DerefMut for Punctuated<T, P> {
122 fn deref_mut(&mut self) -> &mut Self::Target {
123 &mut self.data
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use crate as binread;
131
132 use binread::{io::Cursor, BinRead, BinReaderExt};
133
134 #[derive(BinRead, Clone, Copy, Debug)]
135 #[br(magic = 1u8)]
136 struct One;
137
138 #[derive(BinRead, Clone, Copy, Debug)]
139 #[br(magic = 2u8)]
140 struct Two;
141
142 #[derive(BinRead)]
143 struct PunctuatedTest {
144 count: u8,
145
146 #[br(count = count)]
147 #[br(parse_with = Punctuated::separated)]
148 list: Punctuated<One, Two>,
149 }
150
151 #[derive(BinRead)]
152 struct PunctuatedTestTrailing {
153 count: u8,
154
155 #[br(count = count)]
156 #[br(parse_with = Punctuated::separated_trailing)]
157 list: Punctuated<One, Two>,
158 }
159
160 #[derive(BinRead)]
161 struct MissingCount {
162 #[br(parse_with = Punctuated::separated)]
163 _list: Punctuated<One, Two>,
164 }
165
166 #[derive(BinRead)]
167 struct MissingCountTrailing {
168 #[br(parse_with = Punctuated::separated_trailing)]
169 _list: Punctuated<One, Two>,
170 }
171
172 const TEST_DATA: &[u8] = b"\x03\x01\x02\x01\x02\x01";
173 const TEST_DATA_TRAILING: &[u8] = b"\x03\x01\x02\x01\x02\x01\x02";
174
175 #[test]
176 fn punctuated() {
177 let mut x = Cursor::new(TEST_DATA);
178
179 let y: PunctuatedTest = x.read_be().unwrap();
180
181 assert_eq!(y.count, 3);
182 assert_eq!(y.list.len(), 3);
183
184 assert_eq!(format!("{:?}", y.list), "[One, One, One]");
186 }
187
188 #[test]
189 fn punctuated_trailing() {
190 let mut x = Cursor::new(TEST_DATA_TRAILING);
191
192 let mut y: PunctuatedTestTrailing = x.read_be().unwrap();
193
194 assert_eq!(y.count, 3);
195 assert_eq!(y.list.len(), 3);
196
197 let y = &mut *y.list;
198 y[0] = y[1];
199 }
200
201 #[test]
202 #[should_panic]
203 fn missing_count() {
204 let mut x = Cursor::new(TEST_DATA);
205
206 let _: MissingCount = x.read_be().unwrap();
207 }
208
209 #[test]
210 #[should_panic]
211 fn missing_count_trailing() {
212 let mut x = Cursor::new(TEST_DATA);
213
214 let _: MissingCountTrailing = x.read_be().unwrap();
215 }
216}