@@ -16,6 +16,8 @@ use core::iter::from_fn;
16
16
///
17
17
/// # Examples
18
18
///
19
+ /// Reading null-terminated data:
20
+ ///
19
21
/// ```
20
22
/// # use binrw::{BinRead, helpers::until, io::Cursor, BinReaderExt};
21
23
/// #[derive(BinRead)]
@@ -28,17 +30,53 @@ use core::iter::from_fn;
28
30
/// # let x: NullTerminated = x.read_be().unwrap();
29
31
/// # assert_eq!(x.data, &[1, 2, 3, 4, 0]);
30
32
/// ```
31
- pub fn until < Ret , T , Arg , CondFn , Reader > (
33
+ ///
34
+ /// Reading byte-terminated data with a header that is used to read entries:
35
+ ///
36
+ /// ```
37
+ /// # // This test is checking to make sure that borrowed arguments work.
38
+ /// #
39
+ /// # use binrw::{BinRead, helpers::until, io::Cursor, BinReaderExt};
40
+ /// #[derive(BinRead)]
41
+ /// struct Header {
42
+ /// terminator: u8,
43
+ /// extra: u8,
44
+ /// };
45
+ ///
46
+ /// #[derive(BinRead)]
47
+ /// # #[derive(Debug, Eq, PartialEq)]
48
+ /// #[br(import(header: &Header))]
49
+ /// struct Entry(
50
+ /// #[br(map = |value: u8| value + header.extra)]
51
+ /// u8
52
+ /// );
53
+ ///
54
+ /// #[derive(BinRead)]
55
+ /// struct ByteTerminated {
56
+ /// header: Header,
57
+ ///
58
+ /// #[br(
59
+ /// parse_with = until(|entry: &Entry| entry.0 == header.terminator),
60
+ /// args(&header)
61
+ /// )]
62
+ /// data: Vec<Entry>,
63
+ /// }
64
+ ///
65
+ /// # let mut x = Cursor::new(b"\xff\x01\x02\x03\x04\xfe");
66
+ /// # let x: ByteTerminated = x.read_be().unwrap();
67
+ /// # assert_eq!(x.data, &[Entry(3), Entry(4), Entry(5), Entry(255)]);
68
+ /// ```
69
+ pub fn until < ' a , Ret , T , Arg , CondFn , Reader > (
32
70
cond : CondFn ,
33
71
) -> impl Fn ( & mut Reader , Endian , Arg ) -> BinResult < Ret >
34
72
where
35
73
Ret : FromIterator < T > ,
36
- T : for < ' a > BinRead < Args < ' a > = Arg > ,
74
+ T : BinRead < Args < ' a > = Arg > ,
37
75
Arg : Clone ,
38
76
CondFn : Fn ( & T ) -> bool ,
39
77
Reader : Read + Seek ,
40
78
{
41
- until_with ( cond , T :: read_options )
79
+ use_with ! ( until_with , T , cond )
42
80
}
43
81
44
82
/// Creates a parser that uses a given function to read items into a collection
@@ -108,6 +146,8 @@ where
108
146
///
109
147
/// # Examples
110
148
///
149
+ /// Reading null-terminated data:
150
+ ///
111
151
/// ```
112
152
/// # use binrw::{BinRead, helpers::until_exclusive, io::Cursor, BinReaderExt};
113
153
/// #[derive(BinRead)]
@@ -120,17 +160,52 @@ where
120
160
/// # let x: NullTerminated = x.read_be().unwrap();
121
161
/// # assert_eq!(x.data, &[1, 2, 3, 4]);
122
162
/// ```
123
- pub fn until_exclusive < Ret , T , Arg , CondFn , Reader > (
163
+ ///
164
+ /// Reading byte-terminated data with a header that is required to read entries:
165
+ ///
166
+ /// ```
167
+ /// # // This test is checking to make sure that borrowed arguments work.
168
+ /// #
169
+ /// # use binrw::{BinRead, helpers::until_exclusive, io::Cursor, BinReaderExt};
170
+ /// #[derive(BinRead)]
171
+ /// struct Header {
172
+ /// terminator: u8,
173
+ /// extra: u8,
174
+ /// };
175
+ ///
176
+ /// #[derive(BinRead)]
177
+ /// # #[derive(Debug, Eq, PartialEq)]
178
+ /// #[br(import(header: &Header))]
179
+ /// struct Entry(
180
+ /// #[br(map = |value: u8| value + header.extra)]
181
+ /// u8
182
+ /// );
183
+ ///
184
+ /// #[derive(BinRead)]
185
+ /// struct ByteTerminated {
186
+ /// header: Header,
187
+ ///
188
+ /// #[br(parse_with = until_exclusive(|entry: &Entry| {
189
+ /// entry.0 == header.terminator
190
+ /// }), args(&header))]
191
+ /// data: Vec<Entry>,
192
+ /// }
193
+ ///
194
+ /// # let mut x = Cursor::new(b"\xff\x01\x02\x03\x04\xfe");
195
+ /// # let x: ByteTerminated = x.read_be().unwrap();
196
+ /// # assert_eq!(x.data, &[Entry(3), Entry(4), Entry(5)]);
197
+ /// ```
198
+ pub fn until_exclusive < ' a , Ret , T , Arg , CondFn , Reader > (
124
199
cond : CondFn ,
125
200
) -> impl Fn ( & mut Reader , Endian , Arg ) -> BinResult < Ret >
126
201
where
127
202
Ret : FromIterator < T > ,
128
- T : for < ' a > BinRead < Args < ' a > = Arg > ,
203
+ T : BinRead < Args < ' a > = Arg > ,
129
204
Arg : Clone ,
130
205
CondFn : Fn ( & T ) -> bool ,
131
206
Reader : Read + Seek ,
132
207
{
133
- until_exclusive_with ( cond , T :: read_options )
208
+ use_with ! ( until_exclusive_with , T , cond )
134
209
}
135
210
136
211
/// Creates a parser that uses a given function to read items into a collection
@@ -199,6 +274,8 @@ where
199
274
///
200
275
/// # Examples
201
276
///
277
+ /// Reading an entire file at once:
278
+ ///
202
279
/// ```
203
280
/// # use binrw::{BinRead, helpers::until_eof, io::Cursor, BinReaderExt};
204
281
/// #[derive(BinRead)]
@@ -211,18 +288,50 @@ where
211
288
/// # let x: EntireFile = x.read_be().unwrap();
212
289
/// # assert_eq!(x.data, &[1, 2, 3, 4]);
213
290
/// ```
214
- pub fn until_eof < Ret , T , Arg , Reader > (
291
+ ///
292
+ /// Reading an entire file with a header that is used to read entries:
293
+ ///
294
+ /// ```
295
+ /// # // This test is checking to make sure that borrowed arguments work.
296
+ /// #
297
+ /// # use binrw::{BinRead, helpers::until_eof, io::Cursor, BinReaderExt};
298
+ /// #[derive(BinRead)]
299
+ /// struct Header {
300
+ /// extra: u8,
301
+ /// };
302
+ ///
303
+ /// #[derive(BinRead)]
304
+ /// # #[derive(Debug, Eq, PartialEq)]
305
+ /// #[br(import(header: &Header))]
306
+ /// struct Entry(
307
+ /// #[br(map = |value: u8| value + header.extra)]
308
+ /// u8
309
+ /// );
310
+ ///
311
+ /// #[derive(BinRead)]
312
+ /// struct EntireFile {
313
+ /// header: Header,
314
+ ///
315
+ /// #[br(parse_with = until_eof, args(&header))]
316
+ /// data: Vec<Entry>,
317
+ /// }
318
+ ///
319
+ /// # let mut x = Cursor::new(b"\x01\x02\x03\x04");
320
+ /// # let x: EntireFile = x.read_be().unwrap();
321
+ /// # assert_eq!(x.data, &[Entry(3), Entry(4), Entry(5)]);
322
+ /// ```
323
+ pub fn until_eof < ' a , Ret , T , Arg , Reader > (
215
324
reader : & mut Reader ,
216
325
endian : Endian ,
217
326
args : Arg ,
218
327
) -> BinResult < Ret >
219
328
where
220
329
Ret : FromIterator < T > ,
221
- T : for < ' a > BinRead < Args < ' a > = Arg > ,
330
+ T : BinRead < Args < ' a > = Arg > ,
222
331
Arg : Clone ,
223
332
Reader : Read + Seek ,
224
333
{
225
- until_eof_with ( T :: read_options ) ( reader, endian, args)
334
+ use_with ! ( until_eof_with , T ) ( reader, endian, args)
226
335
}
227
336
228
337
/// Creates a parser that uses a given function to read items into a collection
@@ -359,13 +468,7 @@ where
359
468
It : IntoIterator < Item = Arg > ,
360
469
Reader : Read + Seek ,
361
470
{
362
- // For an unknown reason (possibly related to the note in the compiler error
363
- // that says “due to current limitations in the borrow checker”), trying to
364
- // pass `T::read_options` directly does not work, but passing a closure like
365
- // this works just fine
366
- args_iter_with ( it, |reader, options, arg| {
367
- T :: read_options ( reader, options, arg)
368
- } )
471
+ use_with ! ( args_iter_with, T , it)
369
472
}
370
473
371
474
/// Creates a parser that uses a given function to build a collection, using
@@ -430,6 +533,8 @@ where
430
533
///
431
534
/// # Examples
432
535
///
536
+ /// Reading data of a fixed size:
537
+ ///
433
538
/// ```
434
539
/// # use binrw::{BinRead, helpers::count, io::Cursor, BinReaderExt};
435
540
/// # use std::collections::VecDeque;
@@ -445,6 +550,40 @@ where
445
550
/// # let x: CountBytes = x.read_be().unwrap();
446
551
/// # assert_eq!(x.data, &[1, 2, 3]);
447
552
/// ```
553
+ ///
554
+ /// Reading fixed-size data with a header that is used to read entries:
555
+ ///
556
+ /// ```
557
+ /// # // This test is checking to make sure that borrowed arguments work.
558
+ /// #
559
+ /// # use binrw::{BinRead, helpers::count, io::Cursor, BinReaderExt};
560
+ /// # use std::collections::VecDeque;
561
+ /// #[derive(BinRead)]
562
+ /// struct Header {
563
+ /// len: u8,
564
+ /// extra: u8,
565
+ /// };
566
+ ///
567
+ /// #[derive(BinRead)]
568
+ /// # #[derive(Debug, Eq, PartialEq)]
569
+ /// #[br(import(header: &Header))]
570
+ /// struct Entry(
571
+ /// #[br(map = |value: u8| value + header.extra)]
572
+ /// u8
573
+ /// );
574
+ ///
575
+ /// #[derive(BinRead)]
576
+ /// struct CountBytes {
577
+ /// header: Header,
578
+ ///
579
+ /// #[br(parse_with = count(header.len.into()), args(&header))]
580
+ /// data: VecDeque<Entry>,
581
+ /// }
582
+ ///
583
+ /// # let mut x = Cursor::new(b"\x02\x01\x02\x03");
584
+ /// # let x: CountBytes = x.read_be().unwrap();
585
+ /// # assert_eq!(x.data, &[Entry(3), Entry(4)]);
586
+ /// ```
448
587
pub fn count < ' a , Ret , T , Arg , Reader > (
449
588
n : usize ,
450
589
) -> impl Fn ( & mut Reader , Endian , Arg ) -> BinResult < Ret >
@@ -615,6 +754,22 @@ fn not_enough_bytes<T>(_: T) -> Error {
615
754
) )
616
755
}
617
756
757
+ // For an unknown reason (possibly related to the note in the compiler error
758
+ // that says “due to current limitations in the borrow checker”), passing
759
+ // `T::read_options` directly to any of the `with` helper functions does
760
+ // not work (“requires that `'a` must outlive `'static`” and “one type is more
761
+ // general than the other”), but passing a closure that calls `T::read_options`
762
+ // itself works fine
763
+ macro_rules! use_with {
764
+ ( $fn: ident, $Ty: ty $( , $args: tt) * $( , ) ?) => {
765
+ $fn( $( $args, ) * |reader, options, args| {
766
+ <$Ty>:: read_options( reader, options, args)
767
+ } )
768
+ }
769
+ }
770
+
771
+ use use_with;
772
+
618
773
macro_rules! vec_fast_int {
619
774
( try ( $( $Ty: ty) +) using ( $list: expr, $reader: expr, $endian: expr, $count: expr) else { $( $else: tt) * } ) => {
620
775
$( if let Some ( list) = <dyn core:: any:: Any >:: downcast_mut:: <Vec <$Ty>>( & mut $list) {
0 commit comments