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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
use std::vec::Vec;
use std::cell::RefCell;
use std::rc::Rc;
use std::cmp;
use rand::{Rng, sample, StdRng, SeedableRng};
use soliton::IdealSoliton;
#[derive(Clone, Debug)]
pub enum EncoderType {
/// The first k symbols of a systematic Encoder correspond to the first k source symbols
/// In case there is no loss, no repair needed. After the first k symbols are sent, it continous
/// like in the Random case.
Systematic,
/// Begins immediately with random encoding.
/// This may be a better choice when used with high-loss channels.
Random,
}
/// Encoder for Luby transform codes
pub struct Encoder {
data: Vec<u8>,
len: usize,
blocksize: usize,
rng: StdRng,
cnt_blocks: usize,
sol: IdealSoliton,
cnt: usize,
encodertype: EncoderType,
}
#[derive(Debug)]
enum DropType {
/// First is seed, second degree
Seeded(usize, usize),
/// Just a list of edges
Edges(Vec<usize>),
}
/// A Droplet is created by the Encoder.
#[derive(Debug)]
pub struct Droplet {
/// The droptype can be based on seed or a list of edges
droptype: DropType,
/// The payload of the Droplet
data: Vec<u8>,
}
impl Droplet {
fn new(droptype: DropType, data: Vec<u8>) -> Droplet {
Droplet {
droptype: droptype,
data: data,
}
}
}
impl Encoder {
/// Constructs a new encoder for Luby transform codes.
/// In case you send the packages over UDP, the blocksize
/// should be the MTU size.
///
/// There are two versions of the 'Encoder', Systematic and Random.
/// The Systematic encoder first produces a set of the source symbols. After each
/// symbol is sent once, it switches to Random.
///
/// The Encoder implements the iterator. You can use the iterator
/// to produce an infinte stream of Droplets
///
/// # Examples
///
/// ```
/// extern crate rand;
/// extern crate fountaincode;
///
/// fn main() {
/// use fountaincode::ltcode::{Encoder, EncoderType};
/// use self::rand::{thread_rng, Rng};
///
/// let s:String = thread_rng().gen_ascii_chars().take(1_024).collect();
/// let buf = s.into_bytes();
///
/// let mut enc = Encoder::new(buf, 64, EncoderType::Random);
///
/// for i in 1..10 {
/// println!("droplet {:?}: {:?}", i, enc.next());
/// }
/// }
/// ```
pub fn new(data: Vec<u8>, blocksize: usize, encodertype: EncoderType) -> Encoder {
let mut rng = StdRng::new().unwrap();
let len = data.len();
let cnt_blocks = ((len as f32) / blocksize as f32).ceil() as usize;
let sol = IdealSoliton::new(cnt_blocks, rng.gen::<usize>());
Encoder {
data: data,
len: len,
blocksize: blocksize,
rng: rng,
cnt_blocks: cnt_blocks,
sol: sol,
cnt: 0,
encodertype: encodertype,
}
}
}
fn get_sample_from_rng_by_seed(seed: usize, n: usize, degree: usize) -> Vec<usize> {
let seedarr: &[_] = &[seed];
let mut rng: StdRng = SeedableRng::from_seed(seedarr);
sample(&mut rng, 0..n, degree)
}
impl Iterator for Encoder {
type Item = Droplet;
fn next(&mut self) -> Option<Droplet> {
let drop = match self.encodertype {
EncoderType::Random => {
let degree = self.sol.next().unwrap() as usize; //TODO: try! macro
let seed = self.rng.gen::<u32>() as usize;
let sample = get_sample_from_rng_by_seed(seed, self.cnt_blocks, degree);
let mut r: Vec<u8> = vec![0; self.blocksize];
for k in sample {
let begin = k * self.blocksize;
let end = cmp::min((k + 1) * self.blocksize, self.len);
let mut j = 0;
for i in begin..end {
r[j] ^= self.data[i];
j += 1;
}
}
Some(Droplet::new(DropType::Seeded(seed, degree), r))
}
EncoderType::Systematic => {
let begin = self.cnt * self.blocksize;
let end = cmp::min((self.cnt + 1) * self.blocksize, self.len);
let mut r: Vec<u8> = vec![0; self.blocksize];
let mut j = 0;
for i in begin..end {
r[j] = self.data[i];
j += 1;
}
if (self.cnt + 2) > self.cnt_blocks {
self.encodertype = EncoderType::Random;
}
Some(Droplet::new(DropType::Edges(vec![self.cnt]), r))
}
};
self.cnt += 1;
drop
}
}
/// Decoder for the Luby transform
pub struct Decoder {
total_length: usize,
blocksize: usize,
unknown_chunks: usize,
number_of_chunks: usize,
cnt_received_drops: usize,
blocks: Vec<Block>,
data: Vec<u8>,
}
#[derive(Debug)]
pub struct Statistics {
pub cnt_droplets: usize,
pub cnt_chunks: usize,
pub overhead: f32,
pub unknown_chunks: usize,
}
#[derive(Debug)]
pub enum CatchResult {
Finished(Vec<u8>, Statistics),
Missing(Statistics),
}
#[derive(Debug)]
struct RxDroplet {
edges_idx: Vec<usize>,
data: Vec<u8>,
}
struct Block {
idx: usize,
edges: Vec<Rc<RefCell<RxDroplet>>>,
begin_at: usize,
is_known: bool,
}
impl Decoder {
/// Creates a new Decoder for LT codes
///
/// # Example
///
/// ```
/// extern crate rand;
/// extern crate fountaincode;
///
/// fn main() {
/// use fountaincode::ltcode::{Encoder, EncoderType, Decoder};
/// use fountaincode::ltcode::CatchResult::*;
/// use self::rand::{thread_rng, Rng};
///
/// let s:String = thread_rng().gen_ascii_chars().take(1_024).collect();
/// let buf = s.into_bytes();
/// let to_compare = buf.clone();
/// let length = buf.len();
///
/// let mut enc = Encoder::new(buf, 64, EncoderType::Random);
/// let mut dec = Decoder::new(length, 64);
///
/// for drop in enc {
/// match dec.catch(drop) {
/// Missing(stats) => {
/// println!("Missing blocks {:?}", stats);
/// }
/// Finished(data, stats) => {
/// for i in 0..length {
/// assert_eq!(to_compare[i], data[i]);
/// }
/// println!("Finished, stas: {:?}", stats);
/// //write data to disk??
/// return
/// }
/// }
/// }
/// }
/// ```
pub fn new(len: usize, blocksize: usize) -> Decoder {
let number_of_chunks = ((len as f32) / blocksize as f32).ceil() as usize;
let data: Vec<u8> = vec![0; number_of_chunks * blocksize];
let mut edges: Vec<Block> = Vec::with_capacity(number_of_chunks);
for i in 0..number_of_chunks {
let blk = Block {
idx: i,
edges: Vec::new(),
begin_at: blocksize * i,
is_known: false,
};
edges.push(blk);
}
Decoder {
total_length: len,
number_of_chunks: number_of_chunks,
unknown_chunks: number_of_chunks,
cnt_received_drops: 0,
blocks: edges,
data: data,
blocksize: blocksize,
}
}
fn process_droplet(&mut self, droplet: RxDroplet) {
let mut drops: Vec<Rc<RefCell<RxDroplet>>> = Vec::new();
drops.push(Rc::new(RefCell::new(droplet)));
loop {
// a loop is used instead of recursion
match drops.pop() {
None => return,
Some(drop) => {
let edges = drop.borrow().edges_idx.clone();
// TODO: Maybe add shortcut for the first wave of
// systematic codes, reduce overhead
for ed in edges {
// the list is edited, hence we copy first
let block = self.blocks.get_mut(ed).unwrap();
if block.is_known {
let mut b_drop = drop.borrow_mut();
for i in 0..self.blocksize {
b_drop.data[i] ^= self.data[block.begin_at + i];
}
let pos = b_drop.edges_idx.iter().position(|x| x == &ed).unwrap();
b_drop.edges_idx.remove(pos);
} else {
block.edges.push(drop.clone());
}
}
if drop.borrow().edges_idx.len() == 1 {
let first_idx = drop.borrow().edges_idx.clone().get(0).unwrap().clone();
let block = self.blocks.get_mut(first_idx).unwrap();
if block.is_known == false {
{
let b_drop = drop.borrow();
for i in 0..self.blocksize {
self.data[block.begin_at + i] = b_drop.data[i];
}
}
block.is_known = true;
self.unknown_chunks -= 1;
while block.edges.len() > 0 {
let edge = block.edges.pop().unwrap();
let mut m_edge = edge.borrow_mut();
if m_edge.edges_idx.len() == 1 {
drops.push(edge.clone());
} else {
for i in 0..self.blocksize {
m_edge.data[i] ^= self.data[block.begin_at + i]
}
let pos = m_edge.edges_idx
.iter()
.position(|x| x == &block.idx)
.unwrap();
m_edge.edges_idx.remove(pos);
if m_edge.edges_idx.len() == 1 {
drops.push(edge.clone());
}
}
}
}
}
}
}
}
}
/// Catches a Droplet
/// When it is possible to reconstruct a set, the bytes are returned
pub fn catch(&mut self, drop: Droplet) -> CatchResult {
self.cnt_received_drops += 1;
let sample: Vec<usize> = match drop.droptype {
DropType::Seeded(seed, degree) => {
get_sample_from_rng_by_seed(seed, self.number_of_chunks, degree)
}
DropType::Edges(edges) => edges,
};
let rxdrop = RxDroplet {
edges_idx: sample,
data: drop.data,
};
self.process_droplet(rxdrop);
let stats = Statistics {
cnt_droplets: self.cnt_received_drops,
cnt_chunks: self.number_of_chunks,
overhead: self.cnt_received_drops as f32 * 100.0 / self.number_of_chunks as f32,
unknown_chunks: self.unknown_chunks,
};
if self.unknown_chunks == 0 {
let mut result = Vec::with_capacity(self.total_length);
for i in 0..self.total_length {
// TODO: we should be able to do that without copying
result.push(self.data[i]);
}
CatchResult::Finished(result, stats)
} else {
CatchResult::Missing(stats)
}
}
}