1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! This module defines the [`BufPolicy`](trait.BufPolicy.html) trait,
//! which configures how the internal buffer of the parsers should grow upon
//! encountering large sequences that don't fit into the buffer.
//!
//! The standard policy ([`DoubleUntil`](struct.DoubleUntil.html))
//! causes the initial buffer to double its size until a certain limit, and
//! to further grow linearly above the limit. However, it does not
//! impose a hard limit on buffer size, which may be problematic in some cases.
//! For this purpose we can use
//! [`DoubleUntilLimited`](struct.DoubleUntilLimited.html),
//! or implement our own solution, as shown:
//!
//! ```no_run
//! # fn main() {
//! use seq_io::policy::BufPolicy;
//! use seq_io::fasta::{Reader,Record};
//! use std::io::stdin;
//!
//! struct Max1G;
//!
//! // This policy lets the buffer double each time, but
//! // limits the buffer size to 1 GiB. Note that this is similar to how
//! // `DoubleUntilLimited` works.
//! impl BufPolicy for Max1G {
//!     fn grow_to(&mut self, current_size: usize) -> Option<usize> {
//!         if current_size > 1 << 30 {
//!             return None
//!         }
//!         Some(current_size * 2)
//!     }
//! }
//!
//! let mut reader = Reader::new(stdin()).set_policy(Max1G);
//!
//! while let Some(record) = reader.next() {
//!     println!("{}", record.unwrap().id().unwrap());
//! }
//! # }
//! ```

/// Policy that configures how the internal buffer grows upon
/// encountering large sequences.
///
/// Takes the current buffer size in bytes and returns the new
/// size the the buffer should grow to. Returning `None` instead will indicate
/// that the buffer has grown too big. In this case, the FASTA and FASTQ readers
/// will return `Error::BufferLimit`.
pub trait BufPolicy {
    fn grow_to(&mut self, current_size: usize) -> Option<usize>;
}

/// Standard buffer policy: This policy corresponds to
/// `DoubleUntil(8 * 1024 * 1024)`, meaning that buffer size
/// doubles until it reaches 8 MiB. Above, it will
/// increase in steps of 8 MiB. Buffer size is not limited,
/// it could theoretically grow indefinitely.
pub struct StdPolicy;

impl BufPolicy for StdPolicy {
    fn grow_to(&mut self, current_size: usize) -> Option<usize> {
        Some(if current_size < 1 << 23 {
            current_size * 2
        } else {
            current_size + (1 << 23)
        })
    }
}

/// Buffer size doubles until it reaches a given limit
/// (in bytes). Above, it will increase linearly in
/// steps of 'limit'. Buffer size is not limited,
/// it could theoretically grow indefinitely.
pub struct DoubleUntil(pub usize);

impl BufPolicy for DoubleUntil {
    fn grow_to(&mut self, current_size: usize) -> Option<usize> {
        Some(if current_size < self.0 {
            current_size * 2
        } else {
            current_size + self.0
        })
    }
}

/// Buffer size doubles until it reaches a given limit
/// (in bytes). Above, it will increase linearly in
/// steps of 'double_until'. Buffer size is additionally
/// limited to `limit` bytes. Readers will return an error
/// if this limit is .
pub struct DoubleUntilLimited {
    double_until: usize,
    limit: usize,
}

impl DoubleUntilLimited {
    pub fn new(double_until: usize, limit: usize) -> Self {
        DoubleUntilLimited {
            double_until,
            limit,
        }
    }
}

impl BufPolicy for DoubleUntilLimited {
    fn grow_to(&mut self, current_size: usize) -> Option<usize> {
        let new_size = if current_size < self.double_until {
            current_size * 2
        } else {
            current_size + self.double_until
        };
        if new_size <= self.limit {
            Some(new_size)
        } else {
            None
        }
    }
}