1
use std::collections::VecDeque;
2
use std::io::Error;
3
use std::io::ErrorKind;
4
use std::io::Read;
5
use std::io::Write;
6

            
7
use merc_collections::IndexedSet;
8
use merc_io::BitStreamRead;
9
use merc_io::BitStreamReader;
10
use merc_io::BitStreamWrite;
11
use merc_io::BitStreamWriter;
12
use merc_number::bits_for_value;
13
use merc_utilities::MercError;
14
use merc_utilities::debug_trace;
15

            
16
use crate::ATerm;
17
use crate::ATermInt;
18
use crate::ATermIntRef;
19
use crate::ATermRef;
20
use crate::Protected;
21
use crate::Symb;
22
use crate::Symbol;
23
use crate::SymbolRef;
24
use crate::Term;
25
use crate::is_int_symbol;
26
use crate::is_int_term;
27
use crate::storage::THREAD_TERM_POOL;
28

            
29
/// The magic value for a binary aterm format stream.
30
/// As of version 0x8305 the magic and version are written as 2 bytes not encoded as variable-width integers.
31
/// To ensure compatibility with older formats the previously variable-width encoding is mimicked by prefixing them with 1000 (0x8).
32
const BAF_MAGIC: u16 = 0x8baf;
33

            
34
/// The BAF_VERSION constant is the version number of the ATerms written in BAF format.
35
/// History:
36
/// - before 2013: version 0x0300
37
/// - 29 August 2013: version changed to 0x0301
38
/// - 23 November 2013: version changed to 0x0302 (introduction of index for variable types)
39
/// - 24 September 2014: version changed to 0x0303 (introduction of stochastic distribution)
40
/// - 2 April 2017: version changed to 0x0304 (removed a few superfluous fields in the format)
41
/// - 19 July 2019: version changed to 0x8305 (introduction of the streamable aterm format)
42
/// - 28 February 2020: version changed to 0x8306 (added ability to stream aterm_int,
43
///   implemented structured streaming for all objects)
44
/// - 24 January 2023: version changed to 0x8307 (removed NoIndex from Variables, Boolean variables.
45
///   Made the .lts format more compact by not storing states with a default probability 1)
46
/// - 6 August 2024: version changed to 0x8308 (introduced machine numbers)
47
const BAF_VERSION: u16 = 0x8308;
48

            
49
/// Each packet has a header consisting of a type.
50
/// Either indicates a function symbol, a term (either shared or output) or an arbitrary integer.
51
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52
#[repr(u8)]
53
enum PacketType {
54
    FunctionSymbol = 0,
55
    ATerm = 1,
56
    ATermOutput = 2,
57
    ATermIntOutput = 3,
58
}
59

            
60
/// The number of bits needed to store an element of PacketType.
61
const PACKET_BITS: u8 = 2;
62

            
63
impl From<u8> for PacketType {
64
9431873
    fn from(value: u8) -> Self {
65
9431873
        match value {
66
43580
            0 => PacketType::FunctionSymbol,
67
89525
            1 => PacketType::ATerm,
68
4671850
            2 => PacketType::ATermOutput,
69
4626918
            3 => PacketType::ATermIntOutput,
70
            // Unreachable in practice: every caller derives `value` from `read_bits(PACKET_BITS)`
71
            // with `PACKET_BITS == 2`, so it is always in `0..=3`. Kept as a defensive guard.
72
            _ => unreachable!("Invalid packet type: {value}"),
73
        }
74
9431873
    }
75
}
76

            
77
/// Trait for writing ATerms to a stream.
78
pub trait ATermWrite {
79
    /// Writes an ATerm to the stream.
80
    fn write_aterm(&mut self, term: &ATerm) -> Result<(), MercError>;
81

            
82
    /// Writes an iterator of ATerms to the stream.
83
    fn write_aterm_iter<I>(&mut self, iter: I) -> Result<(), MercError>
84
    where
85
        I: ExactSizeIterator<Item = ATerm>;
86

            
87
    /// Flushes any remaining data and writes the end-of-stream marker.
88
    ///
89
    /// This method should be called when you're done writing terms to ensure
90
    /// all data is properly written and the stream is correctly terminated.
91
    fn flush(&mut self) -> Result<(), MercError>;
92
}
93

            
94
/// Trait for reading ATerms from a stream.
95
pub trait ATermRead {
96
    /// Reads the next ATerm from the stream. Returns None when the end of the stream is reached.
97
    fn read_aterm(&mut self) -> Result<Option<ATerm>, MercError>;
98

            
99
    /// Reads an iterator of ATerms from the stream.
100
    fn read_aterm_iter(&mut self) -> Result<impl ExactSizeIterator<Item = Result<ATerm, MercError>>, MercError>;
101
}
102

            
103
/// Trait for objects that can be written to and read from an ATerm stream.
104
pub trait ATermStreamable {
105
    /// Writes the object to the given ATerm writer.
106
    fn write<W: ATermWrite>(&self, writer: &mut W) -> Result<(), MercError>;
107

            
108
    /// Reads the object from the given ATerm reader.
109
    fn read<R: ATermRead>(reader: &mut R) -> Result<Self, MercError>
110
    where
111
        Self: Sized;
112
}
113

            
114
/// Writes terms in a streamable binary aterm format to an output stream.
115
///
116
/// # The streamable aterm format:
117
///
118
/// Aterms (and function symbols) are written as packets (with an identifier in
119
/// the header) and their indices are derived from the number of aterms, resp.
120
/// symbols, that occur before them in this stream. For each term we first
121
/// ensure that its arguments and symbol are written to the stream (avoiding
122
/// duplicates). Then its symbol index followed by a number of indices
123
/// (depending on the arity) for its argments are written as integers. Packet
124
/// headers also contain a special value to indicate that the read term should
125
/// be visible as output as opposed to being only a subterm. The start of the
126
/// stream is a zero followed by a header and a version and a term with function
127
/// symbol index zero indicates the end of the stream.
128
///
129
pub struct BinaryATermWriter<W: Write> {
130
    stream: BitStreamWriter<W>,
131

            
132
    /// Stores the function symbols and the number of bits needed to encode their indices.
133
    function_symbols: Protected<IndexedSet<SymbolRef<'static>>>,
134
    function_symbol_index_width: u8,
135

            
136
    /// Stores the terms and the number of bits needed to encode their indices.
137
    terms: Protected<IndexedSet<ATermRef<'static>>>,
138
    term_index_width: u8,
139

            
140
    /// Indicates whether the stream has been flushed.
141
    flushed: bool,
142

            
143
    /// Local stack to avoid recursive function calls when writing terms.
144
    stack: VecDeque<(ATerm, bool)>,
145
}
146

            
147
impl<W: Write> BinaryATermWriter<W> {
148
    /// Creates a new binary ATerm output stream with the given writer.
149
301
    pub fn new(writer: W) -> Result<Self, MercError> {
150
301
        let mut stream = BitStreamWriter::new(writer);
151

            
152
        // Write the header of the binary aterm format
153
301
        stream.write_bits(0, 8)?;
154
301
        stream.write_bits(BAF_MAGIC as u64, 16)?;
155
301
        stream.write_bits(BAF_VERSION as u64, 16)?;
156

            
157
301
        let mut function_symbols = Protected::new(IndexedSet::new());
158
        // The term with function symbol index 0 indicates the end of the stream
159
301
        let end_of_stream_symbol = Symbol::new("end_of_stream".to_string(), 0);
160
301
        function_symbols.write().insert(end_of_stream_symbol.copy());
161

            
162
301
        Ok(Self {
163
301
            stream,
164
301
            function_symbols,
165
301
            function_symbol_index_width: 1,
166
301
            terms: Protected::new(IndexedSet::new()),
167
301
            term_index_width: 1,
168
301
            stack: VecDeque::new(),
169
301
            flushed: false,
170
301
        })
171
301
    }
172

            
173
    /// \brief Write a function symbol to the output stream.
174
206349
    fn write_function_symbol(&mut self, symbol: &SymbolRef<'_>) -> Result<usize, MercError> {
175
206349
        let (index, inserted) = self.function_symbols.write().insert(symbol.copy());
176

            
177
206349
        if inserted {
178
            // Write the function symbol to the stream
179
2209
            self.stream.write_bits(PacketType::FunctionSymbol as u64, PACKET_BITS)?;
180
2209
            self.stream.write_string(symbol.name())?;
181
2209
            self.stream.write_integer(symbol.arity() as u64)?;
182
2209
            self.function_symbol_index_width = bits_for_value(self.function_symbols.read().len());
183
204140
        }
184

            
185
206349
        Ok(*index)
186
206349
    }
187

            
188
    /// Returns the current bit width needed to encode a function symbol index.
189
206650
    fn function_symbol_index_width(&self) -> u8 {
190
206650
        let expected = bits_for_value(self.function_symbols.read().len());
191
206650
        debug_assert_eq!(
192
            self.function_symbol_index_width, expected,
193
            "function_symbol_index_width does not match bits_for_value",
194
        );
195

            
196
206650
        self.function_symbol_index_width
197
206650
    }
198

            
199
    /// Returns the current bit width needed to encode a term index.
200
207800
    fn term_index_width(&self) -> u8 {
201
207800
        let expected = bits_for_value(self.terms.read().len());
202
207800
        debug_assert_eq!(
203
            self.term_index_width, expected,
204
            "term_index_width does not match bits_for_value",
205
        );
206
207800
        self.term_index_width
207
207800
    }
208
}
209

            
210
impl<W: Write> ATermWrite for BinaryATermWriter<W> {
211
405690
    fn write_aterm(&mut self, term: &ATerm) -> Result<(), MercError> {
212
405690
        self.stack.push_back((term.clone(), false));
213

            
214
1220556
        while let Some((current_term, write_ready)) = self.stack.pop_back() {
215
            // Indicates that this term is output and not a subterm, these should always be written.
216
814866
            let is_output = self.stack.is_empty();
217

            
218
814866
            if !self.terms.read().contains(&current_term.copy()) || is_output {
219
814788
                if write_ready {
220
407394
                    if is_int_term(&current_term) {
221
201045
                        let int_term = ATermIntRef::from(current_term.copy());
222
201045
                        if is_output {
223
                            // If the integer is output, write the header and just an integer
224
201045
                            self.stream.write_bits(PacketType::ATermIntOutput as u64, PACKET_BITS)?;
225
201045
                            self.stream.write_integer(int_term.value() as u64)?;
226
                        } else {
227
                            let symbol_index = self.write_function_symbol(&int_term.get_head_symbol())?;
228

            
229
                            self.stream.write_bits(PacketType::ATerm as u64, PACKET_BITS)?;
230
                            self.stream
231
                                .write_bits(symbol_index as u64, self.function_symbol_index_width())?;
232
                            self.stream.write_integer(int_term.value() as u64)?;
233
                        }
234
                    } else {
235
206349
                        let symbol_index = self.write_function_symbol(&current_term.get_head_symbol())?;
236
206349
                        let packet_type = if is_output {
237
204645
                            PacketType::ATermOutput
238
                        } else {
239
1704
                            PacketType::ATerm
240
                        };
241

            
242
206349
                        self.stream.write_bits(packet_type as u64, PACKET_BITS)?;
243
206349
                        self.stream
244
206349
                            .write_bits(symbol_index as u64, self.function_symbol_index_width())?;
245

            
246
208005
                        for arg in current_term.arguments() {
247
207800
                            let index = self.terms.read().index(&arg).expect("Argument must already be written");
248
207800
                            self.stream.write_bits(*index as u64, self.term_index_width())?;
249
                        }
250
                    }
251

            
252
407394
                    if !is_output {
253
1704
                        let (_, inserted) = self.terms.write().insert(current_term.copy());
254
1704
                        assert!(inserted, "This term should have a new index assigned.");
255
1704
                        self.term_index_width = bits_for_value(self.terms.read().len());
256
405690
                    }
257
                } else {
258
                    // Add current term back to stack for writing after processing arguments
259
407394
                    self.stack.push_back((current_term.clone(), true));
260

            
261
                    // Add arguments to stack for processing first. Two equal
262
                    // arguments are both pushed here, but that does not write
263
                    // the term twice.
264
408950
                    for arg in current_term.arguments() {
265
207800
                        if !self.terms.read().contains(&arg) {
266
1782
                            self.stack.push_back((arg.protect(), false));
267
206022
                        }
268
                    }
269
                }
270
78
            }
271

            
272
            // This term was already written and as such should be skipped. This can happen if
273
            // one term has two equal subterms.
274
        }
275

            
276
405690
        Ok(())
277
405690
    }
278

            
279
605
    fn write_aterm_iter<I>(&mut self, iter: I) -> Result<(), MercError>
280
605
    where
281
605
        I: ExactSizeIterator<Item = ATerm>,
282
    {
283
605
        self.write_aterm(&ATermInt::new(iter.len()))?;
284
2505
        for ldd in iter {
285
2005
            self.write_aterm(&ldd)?;
286
        }
287
605
        Ok(())
288
605
    }
289

            
290
301
    fn flush(&mut self) -> Result<(), MercError> {
291
        // Write the end of stream marker
292
301
        self.stream.write_bits(PacketType::ATerm as u64, PACKET_BITS)?;
293
301
        self.stream.write_bits(0, self.function_symbol_index_width())?;
294
301
        self.stream.flush()?;
295
301
        self.flushed = true;
296
301
        Ok(())
297
301
    }
298
}
299

            
300
impl<W: Write> BitStreamWrite for BinaryATermWriter<W> {
301
    delegate::delegate! {
302
        to self.stream {
303
            fn write_bits(&mut self, value: u64, number_of_bits: u8) -> Result<(), MercError>;
304
            fn write_string(&mut self, s: &str) -> Result<(), MercError>;
305
            fn write_integer(&mut self, value: u64) -> Result<(), MercError>;
306
            fn flush(&mut self) -> Result<(), MercError>;
307
        }
308
    }
309
}
310

            
311
impl<W: Write> Drop for BinaryATermWriter<W> {
312
301
    fn drop(&mut self) {
313
301
        if !self.flushed {
314
100
            ATermWrite::flush(self).expect("Panicked while flushing the stream when dropped");
315
301
        }
316

            
317
301
        self.function_symbols.write().clear();
318
301
        self.terms.write().clear();
319

            
320
        // Perform garbage collection after clearing the terms, since they might become unreachable.
321
301
        THREAD_TERM_POOL.with(|tp| tp.collect_garbage());
322
301
    }
323
}
324

            
325
/// The reader counterpart of [BinaryATermWriter], which reads ATerms from a binary aterm input stream.
326
pub struct BinaryATermReader<R: Read> {
327
    stream: BitStreamReader<R>,
328

            
329
    /// Stores the function symbols read so far, and the width needed to encode their indices.
330
    function_symbols: Protected<Vec<SymbolRef<'static>>>,
331
    function_symbol_index_width: u8,
332

            
333
    /// Stores the terms read so far, and the width needed to encode their indices.
334
    terms: Protected<Vec<ATermRef<'static>>>,
335
    term_index_width: u8,
336

            
337
    /// Indicates whether the end of stream marker has already been encountered.
338
    ended: bool,
339
}
340

            
341
impl<R: Read> BinaryATermReader<R> {
342
    /// Checks for the header and initializes the binary aterm input stream.
343
308
    pub fn new(reader: R) -> Result<Self, MercError> {
344
308
        let mut stream = BitStreamReader::new(reader);
345

            
346
        // Read the binary aterm format header
347
308
        if stream.read_bits(8)? != 0 || stream.read_bits(16)? != BAF_MAGIC as u64 {
348
            return Err(Error::new(ErrorKind::InvalidData, "Missing BAF_MAGIC control sequence").into());
349
308
        }
350

            
351
308
        let version = stream.read_bits(16)?;
352
308
        if version != BAF_VERSION as u64 {
353
            return Err(Error::new(
354
                ErrorKind::InvalidData,
355
                format!("BAF version ({version}) incompatible with expected version ({BAF_VERSION})"),
356
            )
357
            .into());
358
308
        }
359

            
360
        // The term with function symbol index 0 indicates the end of the stream
361
308
        let mut function_symbols = Protected::new(Vec::new());
362
308
        let end_of_stream_symbol = Symbol::new("end_of_stream".to_string(), 0);
363
308
        function_symbols.write().push(end_of_stream_symbol.copy());
364

            
365
308
        Ok(Self {
366
308
            stream,
367
308
            function_symbols,
368
308
            function_symbol_index_width: 1,
369
308
            terms: Protected::new(Vec::new()),
370
308
            term_index_width: 1,
371
308
            ended: false,
372
308
        })
373
308
    }
374

            
375
    /// Returns the current bit width needed to encode a function symbol index.
376
    ///
377
    /// In debug builds, this asserts that the cached width equals the
378
    /// computed width based on the current number of function symbols.
379
211225
    fn function_symbol_index_width(&self) -> u8 {
380
211225
        let expected = bits_for_value(self.function_symbols.read().len());
381
211225
        debug_assert_eq!(
382
            self.function_symbol_index_width, expected,
383
            "function_symbol_index_width does not match bits_for_value",
384
        );
385

            
386
211225
        self.function_symbol_index_width
387
211225
    }
388

            
389
    /// Returns a mutable reference to the underlying bit stream reader.
390
    pub fn stream(&mut self) -> &mut BitStreamReader<R> {
391
        &mut self.stream
392
    }
393

            
394
    /// Returns the current bit width needed to encode a term index.
395
    ///
396
    /// In debug builds, this asserts that the cached width equals the
397
    /// computed width based on the current number of terms.
398
109168
    fn term_index_width(&self) -> u8 {
399
109168
        let expected = bits_for_value(self.terms.read().len());
400
109168
        debug_assert_eq!(
401
            self.term_index_width, expected,
402
            "term_index_width does not match bits_for_value",
403
        );
404
109168
        self.term_index_width
405
109168
    }
406
}
407

            
408
impl<R: Read> ATermRead for BinaryATermReader<R> {
409
408317
    fn read_aterm(&mut self) -> Result<Option<ATerm>, MercError> {
410
408317
        if self.ended {
411
            return Err(Error::new(
412
                ErrorKind::UnexpectedEof,
413
                "Attempted to read_aterm() after end of stream",
414
            )
415
            .into());
416
408317
        }
417

            
418
        loop {
419
415151
            let header = self.stream.read_bits(PACKET_BITS)?;
420
415151
            let packet = PacketType::from(header as u8);
421
415151
            debug_trace!("Read packet: {:?}", packet);
422

            
423
415151
            match packet {
424
                PacketType::FunctionSymbol => {
425
2660
                    let name = self.stream.read_string()?;
426
2660
                    let arity = self.stream.read_integer()? as usize;
427
2660
                    let symbol = Symbol::new(name, arity);
428
2660
                    debug_trace!("Read symbol {symbol}");
429

            
430
2660
                    let mut write_symbols = self.function_symbols.write();
431
                    // Safety: s is pushed into the container on the next line.
432
2660
                    let s = unsafe { write_symbols.protect_symbol(&symbol) };
433
2660
                    write_symbols.push(s);
434
2660
                    self.function_symbol_index_width = bits_for_value(write_symbols.len());
435
                }
436
                PacketType::ATermIntOutput => {
437
201266
                    let value = self.stream.read_integer()?.try_into()?;
438
201266
                    debug_trace!("Output int term: {}", ATermInt::new(value));
439
201266
                    return Ok(Some(ATermInt::new(value).into()));
440
                }
441
                PacketType::ATerm | PacketType::ATermOutput => {
442
211225
                    let symbol_index = self.stream.read_bits(self.function_symbol_index_width())? as usize;
443
211225
                    if symbol_index == 0 {
444
                        // End of stream marker
445
101
                        debug_trace!("End of stream marker reached");
446
101
                        self.ended = true;
447
101
                        return Ok(None);
448
211124
                    }
449

            
450
211124
                    let symbols = self.function_symbols.read();
451
211124
                    let symbol = symbols.get(symbol_index).ok_or(format!(
452
                        "Read invalid function symbol index {symbol_index}, length {}",
453
211124
                        symbols.len()
454
                    ))?;
455

            
456
211124
                    if is_int_symbol(symbol) {
457
68
                        let value = self.stream.read_integer()?.try_into()?;
458
68
                        let term = ATermInt::new(value);
459
68
                        debug_trace!("Read int term: {term}");
460

            
461
68
                        let mut write_terms = self.terms.write();
462
                        // Safety: t is pushed into the container on the next line.
463
68
                        let t = unsafe { write_terms.protect(&term) };
464
68
                        write_terms.push(t);
465
68
                        self.term_index_width = bits_for_value(write_terms.len());
466
                    } else {
467
                        // When the arity is zero, no bits are read for the arguments.
468
211056
                        let num_of_bits = if symbol.arity() > 0 { self.term_index_width() } else { 0 };
469
211056
                        let mut write_terms = self.terms.write();
470

            
471
211056
                        let term = ATerm::try_with_iter(
472
211056
                            symbol,
473
217122
                            (0..symbol.arity()).map(|_| {
474
217117
                                let arg_index = self.stream.read_bits(num_of_bits)? as usize;
475
217117
                                let arg = write_terms.get(arg_index).ok_or(format!(
476
                                    "Read invalid aterm index {arg_index}, length {}",
477
217117
                                    write_terms.len()
478
                                ))?;
479
217117
                                debug_trace!("Read arg: {arg}");
480
217117
                                Ok(arg)
481
217117
                            }),
482
                        )?;
483

            
484
211056
                        if packet == PacketType::ATermOutput {
485
206950
                            debug_trace!("Output term: {term}");
486
206950
                            return Ok(Some(term));
487
4106
                        }
488
4106
                        debug_trace!("Read term: {term}");
489

            
490
                        // Safety: t is pushed into the container on the next line.
491
4106
                        let t = unsafe { write_terms.protect(&term) };
492
4106
                        write_terms.push(t);
493
4106
                        self.term_index_width = bits_for_value(write_terms.len());
494
                    }
495
                }
496
            }
497
        }
498
408317
    }
499

            
500
640
    fn read_aterm_iter(&mut self) -> Result<impl ExactSizeIterator<Item = Result<ATerm, MercError>>, MercError> {
501
640
        if self.ended {
502
            return Err(Error::new(
503
                ErrorKind::UnexpectedEof,
504
                "Attempted to read_aterm_iter() after end of stream",
505
            )
506
            .into());
507
640
        }
508

            
509
640
        let number_of_elements: ATermInt = self
510
640
            .read_aterm()?
511
640
            .ok_or("Missing number of elements for iterator")?
512
640
            .into();
513
640
        Ok(ATermReadIter {
514
640
            reader: self,
515
640
            remaining: number_of_elements.value(),
516
640
        })
517
640
    }
518
}
519

            
520
impl<R: Read> Drop for BinaryATermReader<R> {
521
308
    fn drop(&mut self) {
522
308
        self.function_symbols.write().clear();
523
308
        self.terms.write().clear();
524

            
525
        // Perform garbage collection after clearing the terms, since they might become unreachable.
526
308
        THREAD_TERM_POOL.with(|tp| tp.collect_garbage());
527
308
    }
528
}
529

            
530
impl<R: Read> BitStreamRead for BinaryATermReader<R> {
531
    delegate::delegate! {
532
        to self.stream {
533
39650
            fn read_bits(&mut self, number_of_bits: u8) -> Result<u64, MercError>;
534
            fn read_string(&mut self) -> Result<String, MercError>;
535
13560
            fn read_integer(&mut self) -> Result<u64, MercError>;
536
        }
537
    }
538
}
539

            
540
/// A read iterator for ATerms from a binary aterm input stream.
541
pub struct ATermReadIter<'a, R: Read> {
542
    reader: &'a mut BinaryATermReader<R>,
543
    remaining: usize,
544
}
545

            
546
impl<'a, R: Read> Iterator for ATermReadIter<'a, R> {
547
    type Item = Result<ATerm, MercError>;
548

            
549
2547
    fn next(&mut self) -> Option<Self::Item> {
550
2547
        if self.remaining == 0 {
551
540
            return None;
552
2007
        }
553

            
554
2007
        self.remaining -= 1;
555
2007
        match self.reader.read_aterm() {
556
2007
            Ok(Some(term)) => Some(Ok(term)),
557
            Ok(None) => Some(Err(Error::new(
558
                ErrorKind::UnexpectedEof,
559
                "Unexpected end of stream while reading iterator",
560
            )
561
            .into())),
562
            Err(e) => Some(Err(e)),
563
        }
564
2547
    }
565

            
566
5
    fn size_hint(&self) -> (usize, Option<usize>) {
567
5
        (self.remaining, Some(self.remaining))
568
5
    }
569
}
570

            
571
impl<'a, R: Read> ExactSizeIterator for ATermReadIter<'a, R> {
572
    fn len(&self) -> usize {
573
        self.remaining
574
    }
575
}
576

            
577
#[cfg(test)]
578
mod tests {
579
    use merc_utilities::random_test;
580

            
581
    use crate::ATermRead;
582
    use crate::ATermWrite;
583
    use crate::BinaryATermReader;
584
    use crate::BinaryATermWriter;
585
    use crate::random_term;
586

            
587
    #[test]
588
    #[cfg_attr(miri, ignore)] // Miri is too slow
589
1
    fn test_random_binary_stream() {
590
100
        random_test(100, |rng| {
591
100
            let input: Vec<_> = (0..20)
592
2000
                .map(|_| random_term(rng, &[("f".into(), 2), ("g".into(), 1)], &["a".into(), "b".into()], 1))
593
100
                .collect();
594

            
595
100
            let mut stream: Vec<u8> = Vec::new();
596

            
597
100
            let mut output_stream = BinaryATermWriter::new(&mut stream).unwrap();
598
2000
            for term in &input {
599
2000
                output_stream.write_aterm(term).unwrap();
600
2000
            }
601
100
            ATermWrite::flush(&mut output_stream).expect("Flushing the output to the stream");
602
100
            drop(output_stream); // Explicitly drop to release the mutable borrow
603

            
604
100
            let mut input_stream = BinaryATermReader::new(&stream[..]).unwrap();
605
2000
            for term in &input {
606
2000
                println!("Term {}", term);
607
2000
                debug_assert_eq!(
608
                    *term,
609
2000
                    input_stream.read_aterm().unwrap().unwrap(),
610
                    "The read term must match the term that we have written"
611
                );
612
            }
613
100
        });
614
1
    }
615

            
616
    #[test]
617
    #[cfg_attr(miri, ignore)] // Miri is too slow
618
1
    fn test_random_binary_stream_iter() {
619
100
        random_test(100, |rng| {
620
100
            let input: Vec<_> = (0..20)
621
2000
                .map(|_| random_term(rng, &[("f".into(), 2), ("g".into(), 1)], &["a".into(), "b".into()], 1))
622
100
                .collect();
623

            
624
100
            let mut stream: Vec<u8> = Vec::new();
625

            
626
100
            let mut output_stream = BinaryATermWriter::new(&mut stream).unwrap();
627
100
            output_stream.write_aterm_iter(input.iter().cloned()).unwrap();
628
100
            ATermWrite::flush(&mut output_stream).expect("Flushing the output to the stream");
629
100
            drop(output_stream); // Explicitly drop to release the mutable borrow
630

            
631
100
            let mut input_stream = BinaryATermReader::new(&stream[..]).unwrap();
632
100
            let read_iter = input_stream.read_aterm_iter().unwrap();
633
2000
            for (term_written, term_read) in input.iter().zip(read_iter) {
634
2000
                let term_read = term_read.expect("Reading term from stream must succeed");
635
2000
                println!("Term {}", term_written);
636
2000
                debug_assert_eq!(
637
                    *term_written, term_read,
638
                    "The read term must match the term that we have written"
639
                );
640
            }
641
100
        });
642
1
    }
643
}