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
118
119
120
121
122
123
124
125
126
127
//! Scattered, gathered, immutable, arc-ed data
//!
//! Allows zero-copy processing of streamed data, read into fixed-size buffers.
//! Especially useful for high-performance, parallel data processing.

extern crate owning_ref;

use owning_ref::ArcRef;
use std::io::Write;
use std::sync::Arc;

/// Scattered, gathered, immutable, arc-ed data
///
/// A piece of data potentially scattered between multiple parts, which
/// themselves might be slices of shared-ownership underlying data.
///
/// `SGData` is essentially semantic wrapper over `Vec<ArcRef<Vec<u8>, [u8]>>`
///
///
/// For illustration:
///
/// ``` norust
/// frames:      [    Buf    ][    Buf    ][    Buf    ][    Buf    ]
/// edges:       |                |    |                      |     |
///              |                |    |                      |     |
///               \          /\  / \  / \ /\           /\    / \   /
///                \        /  ||   ||  | | \         /  \  /   \ /
/// sgdata parts:      C1[0] C1[1] C2[0] C3[0]   C3[1]   C3[2]  C4[0]
/// ```
///
/// Arbitrary-sized data is being read into `frames` and edges between
/// logical parts are being found. Then `sgdata` objects are created,
/// aggregating parts of `frames` while holding reference-counted shared
/// ownership over `frames`.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct SGData(Vec<ArcRef<Vec<u8>, [u8]>>);


impl SGData {
    pub fn empty() -> Self {
        SGData::from_many(vec![])
    }

    pub fn from_single(v: Vec<u8>) -> Self {
        SGData::from_many(vec![v])
    }

    pub fn from_vec(v: Vec<ArcRef<Vec<u8>, [u8]>>) -> Self {
        SGData(v)
    }

    pub fn from_many(mut v: Vec<Vec<u8>>) -> Self {
        SGData(
            v.drain(..)
                .map(|v| ArcRef::new(Arc::new(v)).map(|v| &v[..]))
                .collect(),
        )
    }

    /// Total len of all parts
    pub fn len(&self) -> usize {
        self.0.iter().fold(0, |sum, part | sum + part.len())
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn as_parts(&self) -> &[ArcRef<Vec<u8>, [u8]>] {
        &self.0
    }

    pub fn as_vec(&self) -> &Vec<ArcRef<Vec<u8>, [u8]>> {
        &self.0
    }

    pub fn as_vec_mut(&mut self) -> &mut Vec<ArcRef<Vec<u8>, [u8]>> {
        &mut self.0
    }

    pub fn push_vec(&mut self, v : Vec<u8>) {
        self.0.push(ArcRef::new(Arc::new(v)).map(|v| &v[..]))
    }

    pub fn push_arcref(&mut self, arcref : ArcRef<Vec<u8>, [u8]>) {
        self.0.push(arcref)
    }

    /// Convert to linear (single vector) form
    ///
    /// If `self` is empty or already contains only one piece,
    /// this is cheap.
    ///
    /// If `self` is scattered between many pices, this requires
    /// copying all the data into a new, big chunk.
    pub fn to_linear(&self) -> ArcRef<Vec<u8>, [u8]> {
        match self.0.len() {
            0 => ArcRef::new(Arc::new(vec![])).map(|v| &v[..]),
            1 => self.0[0].clone(),
            _ => {
                let mut v = Vec::with_capacity(self.len());
                for sg_part in &self.0 {
                    v.write_all(sg_part).unwrap();
                }
                ArcRef::new(Arc::new(v)).map(|v| &v[..])
            }
        }
    }

    pub fn to_linear_vec(mut self) -> Vec<u8> {
        match self.0.len() {
            0 => vec![],
            1 => {
                let e = self.0.pop().unwrap();
                Arc::try_unwrap(e.into_inner())
                    .unwrap_or_else(|a| a.as_ref().clone())
            }
            _ => {
                let mut v = Vec::with_capacity(self.len());
                for sg_part in &self.0 {
                    v.write_all(sg_part).unwrap();
                }
                v
            }
        }
    }
}