tuple_storage/
lib.rs

1//! Using the tuple_storage as a library or a stand alone binary
2//!
3//! # Installation
4//!
5//! ```bash
6//! $ cargo install tuple_storage
7//! ```
8//!
9//! Find an example usage in the [README](https://gitlab.com/dns2utf8/tuple_storage/blob/master/README.md).
10
11//extern crate fs2;
12extern crate memmap;
13#[cfg(test)]
14extern crate tempfile;
15
16mod mmap_util;
17use mmap_util::*;
18mod iter;
19use iter::*;
20mod filter;
21use filter::*;
22mod ints;
23pub use ints::*;
24
25#[allow(unused_imports)]
26use std::mem::{size_of, size_of_val};
27use std::fs::{File};
28use std::io::{self, Write};
29use std::str::FromStr;
30
31use memmap::{Mmap, MmapMut};
32
33/// The Byte Tag to identify the `Storage`
34pub const MAGIC_NUMBER: u64 = 0x4242_0868_7537_8673;
35/// The file format version
36pub const FILE_FORMAT_VERSION: u16 = 0;
37
38#[derive(Debug)]
39pub struct Storage {
40    header: Header,
41    file: File,
42    mmap: MmapMut,
43}
44
45impl Storage {
46    pub fn create(file: File, schema: &str) -> io::Result<Storage> {
47        let header = Header::new(schema).unwrap();
48        // FIXME random length, can no grow
49        file.set_len(10*1024*1024)?;
50        let mmap = unsafe { MmapMut::map_mut(&file)? };
51
52        let mut s = Storage { header, file, mmap };
53
54        s.persist()?;
55
56        Ok(s)
57    }
58
59    fn calc_required_space(&self) -> u64 {
60        let header = self.header.serialized_size();
61
62        header + self.header.n_tuples * self.header.schema.data_size
63    }
64    fn calc_offset_location(&self, offset: u64) -> u64 {
65        assert!(offset <= self.header.n_tuples, "Storage::calc_offset_location({}) too big - n_tuples: {}", offset, self.header.n_tuples);
66        let header = self.header.serialized_size();
67
68        header + offset * self.header.schema.data_size
69    }
70
71    pub fn persist(&mut self) -> io::Result<()> {
72        let space = self.calc_required_space();
73        self.file.set_len(space)?;
74        self.header.persist(&mut self.mmap);
75        self.mmap.flush()?;
76        Ok( () )
77    }
78
79    pub fn open(file: File) -> io::Result<Storage> {
80        // FIXME random length, can no grow
81        file.set_len(10*1024*1024)?;
82        let mut reader = MmapReader::new(&file)?;
83        let header = Header::open(&mut reader).unwrap();
84        
85        let mmap = unsafe { MmapMut::map_mut(&file)? };
86        Ok(Storage { header, file, mmap })
87    }
88
89    /// Insert does not allow duplicate key and
90    /// inserts the Tuple in the set in a sorted way
91    pub fn insert(&mut self, tuple: &mut Tuple) -> Result<(), SchemaError> {
92        self.header.schema.matches(&tuple)?;
93
94        // TODO optimieren
95        if self.iter().any(|t| t.data[0] == tuple.data[0]) {
96            return Err(SchemaError::DuplicateKey)
97        }
98
99        // add space to memmap
100        let mut current_offset = self.calc_required_space();
101        let new_size = current_offset + self.header.schema.data_size;
102        assert!(self.file.set_len(new_size).is_ok(), "Storage::insert file.set_len({}) failed", new_size);
103        assert!((new_size as usize) <= self.mmap.len(), "Storage::insert: out of mapped space");
104
105        let start = self.iter().enumerate()
106                        .fold(0, |b, (i, t)| {
107                            //println!("i: {}", i);
108                            if t.data[0] < tuple.data[0] {
109                                i as u64
110                            } else {
111                                b
112                            }
113                        });
114        //println!("Storage::insert({:?}) => start {}", tuple, start);
115        if start < self.header.n_tuples {
116            // shift the rest
117            let mut i = self.header.n_tuples;
118            while i > start {
119                //println!("{}", i);
120                let offset = self.calc_offset_location(i);
121                let mut last = self.get(i - 1).expect("Storage::insert moving out of range");
122                let mut writer = MmapWriter::at_offset(
123                                    &mut self.mmap,
124                                    offset as usize);
125                last.persist(&mut writer);
126
127                i -= 1;
128            }
129
130            current_offset = self.calc_offset_location(start);
131        }
132
133        let mut writer = MmapWriter::at_offset(&mut self.mmap, current_offset as usize);
134
135        tuple.persist(&mut writer);
136
137        self.header.n_tuples += 1;
138        Ok( () )
139    }
140
141
142    /// Append allows duplicate key
143    pub fn append(&mut self, tuple: &mut Tuple) -> Result<(), SchemaError> {
144        self.header.schema.matches(&tuple)?;
145
146        // add to memmap
147        let current_offset = self.calc_required_space();
148        let new_size = current_offset + self.header.schema.data_size;
149        assert!(self.file.set_len(new_size).is_ok(), "Storage::append file.set_len({}) failed", new_size);
150        assert!((new_size as usize) <= self.mmap.len(), "Storage::append: out of mapped space");
151
152        let mut writer = MmapWriter::at_offset(&mut self.mmap, current_offset as usize);
153
154        tuple.persist(&mut writer);
155
156        self.header.n_tuples += 1;
157        Ok( () )
158    }
159    
160    /// Update all tuples matching the key
161    /// 
162    /// returns how many tuples were updated
163    pub fn update(&mut self, tuple: &mut Tuple) -> Result<usize, SchemaError> {
164        self.header.schema.matches(tuple)?;
165        let mut count = 0;
166        
167        for i in 0..self.header.n_tuples {
168            let t = self.get(i).expect("Tuple must exist in Range");
169            if tuple.data[0] == t.data[0] {
170                let current_offset = self.header.serialized_size()
171                                    + i as u64 * self.header.schema.data_size;
172                let mut writer = MmapWriter::at_offset(&mut self.mmap, current_offset as usize);
173                tuple.persist(&mut writer);
174                count += 1;
175            }
176        }
177        
178        Ok(count)
179    }
180    
181    /// Remove all tuples matching the key.
182    /// Working from the end to the front of the Storage.
183    pub fn remove_all(&mut self, filter: &Filter) -> usize {
184        //println!("Storage::remove_all");
185        let mut deleted = 0;
186
187        for i in (0..self.header.n_tuples).map(|i| i).rev() {
188            let tuple = self.get(i).expect("in Range access current");
189            //println!("filter.matches({:?}) == {}", tuple, filter.matches(&tuple));
190            if filter.matches(&tuple) {
191                let mut last = self.get(self.header.n_tuples - 1).expect("in Range access last");
192
193                let current_offset = self.calc_offset_location(i);
194                let mut writer = MmapWriter::at_offset(&mut self.mmap, current_offset as usize);
195                last.persist(&mut writer);
196
197                deleted += 1;
198                self.header.n_tuples -= 1;
199            }
200        }
201
202        deleted
203    }
204    /// Delete all tuples matching the key sorted
205    pub fn remove(&mut self, filter: &Filter) -> usize {
206        //println!("Storage::remove({:?})", filter);
207        let mut deleted = 0;
208
209        let mut i = 0;
210        while i < self.header.n_tuples {
211            let tuple = self.get(i).expect("in Range access current");
212            //println!("filter.matches({:?}) == {} | {}", tuple, filter.matches(&tuple), i);
213            if filter.matches(&tuple) {
214                for j in i+1..self.header.n_tuples {
215                    let mut current = self.get(j).expect("in Range access moving");
216                    //println!("    {} => {:?}", j, current);
217                    let offset = self.calc_offset_location(j-1);
218                    let mut writer = MmapWriter::at_offset(&mut self.mmap, offset as usize);
219                    current.persist(&mut writer);
220                }
221
222                deleted += 1;
223                self.header.n_tuples -= 1;
224            } else {
225                i += 1;
226            }
227        }
228
229        deleted
230    }
231
232    pub fn iter(&self) -> StorageIterator {
233        StorageIterator::new(self)
234    }
235    /*pub fn iter_mut(&mut self) -> StorageIteratorMut {
236        StorageIteratorMut::new(self)
237    }*/
238    
239    pub fn get(&self, offset: u64) -> Option<Tuple> {
240        if offset < self.header.n_tuples {
241            let offset = self.calc_offset_location(offset);
242                    
243            let mut reader = MmapReader::at_offset(&self.file, offset as usize).unwrap();
244            
245            Some(Tuple::from(&mut reader, &self.header.schema))
246        } else {
247            None
248        }
249    }
250    
251    pub fn create_filter(&self, filter: &str) -> Result<Filter, SchemaParseError> {
252        Filter::create(&self.header.schema, filter)
253    }
254
255    pub fn schema_to_string(&self) -> String {
256        format!("({})", self.header.schema.schema.join(", "))
257    }
258}
259impl Drop for Storage {
260    fn drop(&mut self) {
261        assert!(self.persist().is_ok());
262        assert!(self.mmap.flush().is_ok());
263        assert!(self.file.flush().is_ok());
264    }
265}
266impl std::cmp::PartialEq for Storage {
267    fn eq(&self, other: &Self) -> bool {
268        self.header == other.header && self.iter().zip(other.iter()).all(|(a, b)| a == b)
269    }
270}
271
272#[derive(Debug, PartialEq)]
273pub struct Header {
274    magic_number: u64,
275    format_version: u16,
276    /// Size of header
277    header_size: u16,
278    n_tuples: u64,
279    schema: Schema,
280}
281
282impl Header {
283    fn new(schema: &str) -> Result<Header, SchemaParseError> {
284        Ok(Header {
285            magic_number: MAGIC_NUMBER,
286            format_version: FILE_FORMAT_VERSION,
287            header_size: Self::base_size(),
288            n_tuples: 0,
289            schema: schema.parse()?,
290        })
291    }
292
293    fn open(reader: &mut MmapReader) -> Result<Header, SchemaParseError> {
294        use SchemaParseError::*;
295
296        if &MAGIC_NUMBER != reader.get() {
297            return Err(InvalidMagicNumber)
298        }
299        if &FILE_FORMAT_VERSION != reader.get() {
300            return Err(InvalidFileFormatVersion)
301        }
302        let header_size = reader.get();
303        if *header_size < Self::base_size() {
304            return Err(HeaderSizeTooSmall(*header_size))
305        }
306        let n_tuples = reader.get();
307
308        let slice = reader.get_str_slice((header_size - Self::base_size()) as usize);
309
310        //println!("##########################\n  extracted schema: {:?}", slice);
311        let schema = slice.parse().unwrap();
312
313
314        Ok(Header {
315            magic_number: MAGIC_NUMBER,
316            format_version: FILE_FORMAT_VERSION,
317            header_size: *header_size,
318            n_tuples: *n_tuples,
319            schema,
320        })
321    }
322
323    fn base_size() -> u16 {
324        let size = size_of::<u64>()
325            + size_of::<u16>()
326            + size_of::<u16>()
327            + size_of::<u64>()
328            // ignore schema
329            ;
330
331        assert!(size <= u16::max_value() as usize, "base_size outgrew data_type {}", size);
332        size as u16
333    }
334
335    fn serialized_size(&self) -> u64 {
336        Self::base_size() as u64 + self.schema.serialized_size()
337    }
338
339    fn persist(&mut self, mmap: &mut MmapMut) {
340        self.header_size = self.serialized_size() as u16;
341
342        let mut writer = MmapWriter::new(mmap);
343
344        writer.append(&self.magic_number);
345        writer.append(&self.format_version);
346        writer.append(&(self.serialized_size() as u16));
347        writer.append(&self.n_tuples);
348
349        self.schema.persist(&mut writer);
350    }
351}
352
353#[derive(Debug, PartialEq)]
354pub struct Schema {
355    schema: Vec<String>,
356    //index_size: u64,
357    data_size: u64,
358}
359
360impl FromStr for Schema {
361    type Err = SchemaParseError;
362
363    fn from_str(s: &str) -> Result<Self, Self::Err> {
364        let schema = s.trim_matches(|p| p == '(' || p == ')' )
365                        .split(",")
366                        .map(|s| s.trim())
367                        .map(|s| {
368                            match s {
369                                "u64" | "i64" | "u32" | "i32" | "u16" | "i16" | "u8" | "i8" => Ok(s.into()),
370                                t => Err(SchemaParseError::InvalidType(t.into()))
371                            }
372                        })
373                        .collect::<Result<Vec<String>, Self::Err>>()?;
374
375        let data_size = schema.iter()
376                            .map(|s: &String| {
377                                match &**s {
378                                    "u64" | "i64" => 8,
379                                    "u32" | "i32" => 4,
380                                    "u16" | "i16" => 2,
381                                    "u8"  |  "i8" => 1,
382                                    _ => panic!("unhandled type {:?}", s),
383                                }
384                            })
385                            .sum();
386
387        Ok(Schema { schema, data_size })
388    }
389
390}
391
392impl Schema {
393    fn serialize_schema(&self) -> String {
394        let mut s = "(".to_string();
395
396        s += &self.schema.join(",");
397
398        s += ")";
399        s
400    }
401
402    fn serialized_size(&self) -> u64 {
403        // TODO
404        self.serialize_schema().len() as u64
405    }
406
407    fn persist(&mut self, writer: &mut MmapWriter) {
408        let schema = self.serialize_schema();
409        writer.append_slice(&schema.as_bytes());
410    }
411
412    fn matches(&self, tuple: &Tuple) -> Result<(), SchemaError> {
413        use SchemaError::*;
414        if self.schema.len() != tuple.data.len() {
415            return Err(MismatchedLength)
416        }
417        for (s, t) in self.schema.iter().zip(tuple.data.iter()) {
418            let t_s = t.str_repr();
419            if s != t_s {
420                return Err(InvalidType(t_s.into()))
421            }
422        }
423        Ok( () )
424    }
425}
426
427#[derive(Debug, PartialEq)]
428pub enum SchemaParseError {
429    InvalidType(String),
430    InvalidMagicNumber,
431    InvalidFileFormatVersion,
432    HeaderSizeTooSmall(u16),
433    FilterInvalidOperand(String),
434}
435
436#[derive(Debug, PartialEq)]
437pub enum SchemaError {
438    MismatchedLength,
439    InvalidType(String),
440    DuplicateKey,
441}
442
443#[derive(Debug, PartialEq)]
444pub struct Tuple {
445    data: Vec<Ints>,
446}
447
448impl Tuple {
449    pub fn new(data: Vec<Ints>) -> Tuple {
450        Tuple { data }
451    }
452    
453    pub fn from(reader: &mut MmapReader, schema: &Schema) -> Tuple {
454        //println!("Tuple::from()");
455        let mut data = vec![];
456        
457        for t in &schema.schema {
458            let x = match &t[..] {
459                "u64" => U64(*reader.get()),
460                "i64" => I64(*reader.get()),
461                "u32" => U32(*reader.get()),
462                "i32" => I32(*reader.get()),
463                "u16" => U16(*reader.get()),
464                "i16" => I16(*reader.get()),
465                "u8"  => U8(*reader.get()),
466                "i8"  => I8(*reader.get()),
467                _ => unimplemented!("Tuple::from({:?}) missing type {:?}", schema, t),
468            };
469            data.push(x);
470        }
471
472        Tuple { data }
473    }
474    
475    pub fn from_str(storage: &Storage, input: &str) -> Tuple {
476        let ref schema = storage.header.schema;
477        Self::from_schema_and_str(schema, input)
478    }
479    
480    fn from_schema_and_str(schema: &Schema, input: &str) -> Tuple {
481        let input = input.trim_matches(|p| p == '(' || p == ')' )
482                        .split(",")
483                        .map(|s| s.trim())
484                        .collect::<Vec<_>>();
485        assert_eq!(schema.schema.len(), input.len(), "Tuple::from_str() input len does not match");
486        
487        let mut data = vec![];
488        
489        for (t, i) in schema.schema.iter().zip(input.iter()) {
490            let x = match &t[..] {
491                "u64" => U64(i.parse().unwrap()),
492                "i64" => I64(i.parse().unwrap()),
493                "u32" => U32(i.parse().unwrap()),
494                "i32" => I32(i.parse().unwrap()),
495                "u16" => U16(i.parse().unwrap()),
496                "i16" => I16(i.parse().unwrap()),
497                "u8"  => U8 (i.parse().unwrap()),
498                "i8"  => I8 (i.parse().unwrap()),
499                _ => unimplemented!("Tuple::from({:?}) missing type {:?}", schema, t),
500            };
501            data.push(x);
502        }
503
504        Tuple { data }
505    }
506    
507    fn persist(&mut self, writer: &mut MmapWriter) {
508        //println!("Tuple::persist({:?})", self);
509        for val in &self.data {
510            match val {
511                U64(value) => writer.append(value),
512                I64(value) => writer.append(value),
513                U32(value) => writer.append(value),
514                I32(value) => writer.append(value),
515                U16(value) => writer.append(value),
516                I16(value) => writer.append(value),
517                U8(value)  => writer.append(value),
518                I8(value)  => writer.append(value),
519            }
520        }
521    }
522    
523    pub fn to_string(&self) -> String {
524        let mut parts = vec![];
525        
526        for val in &self.data {
527            parts.push(match val {
528                U64(value) => format!("{}", value),
529                I64(value) => format!("{}", value),
530                U32(value) => format!("{}", value),
531                I32(value) => format!("{}", value),
532                U16(value) => format!("{}", value),
533                I16(value) => format!("{}", value),
534                U8(value)  => format!("{}", value),
535                I8(value)  => format!("{}", value),
536            });
537        }
538        
539        format!("({})", parts.join(", "))
540    }
541}
542
543
544
545
546#[cfg(test)]
547mod test {
548    use super::*;
549    use tempfile::{TempDir};
550
551
552    fn random_file() -> io::Result<(TempDir, File)> {
553        let dir = tempfile::tempdir()?;
554        println!("{:?}", dir);
555        let path = dir.path().join("demo.ts");
556        let file = std::fs::OpenOptions::new()
557                        .read(true).write(true).create(true)
558                        .open(&path)?;
559
560        Ok((dir, file))
561    }
562
563    /*
564    fn flush_stdout() {
565        let stdout = io::stdout();
566        let mut handle = stdout.lock();
567        handle.flush().is_ok();
568    }
569    */
570
571    #[test]
572    fn serialize_empty() {
573        let expected = [
574            0x73, 0x86, 0x37, 0x75, 0x68, 0x08, 0x42, 0x42,
575            0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00,
576            0x00, 0x00, 0x00, 0x00, 0x28, 0x75, 0x36, 0x34,
577            0x2c, 0x69, 0x36, 0x34, 0x29,
578        ];
579        let (dir, file) = random_file().unwrap();
580        {
581            let mut s = Storage::create(file, "(u64, i64)").unwrap();
582            assert!(s.persist().is_ok());
583            println!("{:?}", s);
584        }
585
586        let r = std::fs::read(dir.path().join("demo.ts")).unwrap();
587
588        assert_eq!(expected, *r);
589
590    }
591
592    #[test]
593    fn deserialize_empty() {
594        let blob = [
595            0x73, 0x86, 0x37, 0x75, 0x68, 0x08, 0x42, 0x42,
596            0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00,
597            0x00, 0x00, 0x00, 0x00, 0x28, 0x75, 0x36, 0x34,
598            0x2c, 0x69, 0x36, 0x34, 0x29,
599        ];
600        let (dir, file) = random_file().unwrap();
601        std::fs::write(dir.path().join("demo.ts"), &blob).is_ok();
602
603        let r = Storage::open(file).unwrap();
604        println!("{:?}", r);
605
606        let (_dir, file) = random_file().unwrap();
607        let expected = Storage::create(file, "(u64, i64)").unwrap();
608
609        assert_eq!(expected, r);
610
611    }
612
613
614
615    #[test]
616    fn serialize_one() {
617        let expected = vec![
618            0x73, 0x86, 0x37, 0x75, 0x68, 0x08, 0x42, 0x42,
619            0x00, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x00,
620            0x00, 0x00, 0x00, 0x00, 0x28, 0x75, 0x36, 0x34,
621            0x2c, 0x69, 0x36, 0x34, 0x29,
622            // Data
623            0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624            0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
625        ];
626        let (dir, file) = random_file().unwrap();
627        {
628            let mut s = Storage::create(file, "(u64, i64)").unwrap();
629            assert!(s.append(&mut Tuple{ data: vec![U64(12), I64(-64)]}).is_ok());
630            assert!(s.persist().is_ok());
631            println!("{:?}", s);
632        }
633
634        let r = std::fs::read(dir.path().join("demo.ts")).unwrap();
635
636        assert_eq!(expected, r, "\n  expected: `{:x?}`\n  read:     `{:x?}`", expected, r);
637    }
638
639    #[test]
640    fn deserialize_one() {
641        let blob = vec![
642            0x73, 0x86, 0x37, 0x75, 0x68, 0x08, 0x42, 0x42,
643            // format version
644            0x00, 0x00,
645            // serialized size
646            0x1d, 0x00,
647            // n_tuples
648            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649            // schema String
650            0x28, 0x75, 0x36, 0x34, 0x2c, 0x69, 0x36, 0x34,
651            0x29,
652            // Data
653            0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654            0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
655        ];
656        let (dir, file) = random_file().unwrap();
657        std::fs::write(dir.path().join("demo.ts"), &blob).is_ok();
658
659        let r = Storage::open(file).unwrap();
660        println!("{:?}", r);
661
662        let (_dir, file) = random_file().unwrap();
663        let mut expected = Storage::create(file, "(u64, i64)").unwrap();
664        assert!(expected.append(&mut Tuple{ data: vec![U64(12), I64(-64)]}).is_ok());
665        assert!(expected.persist().is_ok());
666
667        assert_eq!(expected, r);
668
669        let mut it = expected.iter();
670        let expected = Tuple { data: vec![ U64(12), I64(-64) ]};
671        assert_eq!(Some(expected), it.next());
672        assert_eq!(None, it.next());
673    }
674
675    #[test]
676    fn update_one() {
677        let blob = vec![
678            0x73, 0x86, 0x37, 0x75, 0x68, 0x08, 0x42, 0x42,
679            // format version
680            0x00, 0x00,
681            // serialized size
682            0x1d, 0x00,
683            // n_tuples
684            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685            // schema String
686            0x28, 0x75, 0x36, 0x34, 0x2c, 0x69, 0x36, 0x34,
687            0x29,
688            // Data: (U64(12), I64(-64))
689            0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690            0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
691        ];
692        let expected = vec![
693            0x73, 0x86, 0x37, 0x75, 0x68, 0x08, 0x42, 0x42,
694            // format version
695            0x00, 0x00,
696            // serialized size
697            0x1d, 0x00,
698            // n_tuples
699            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
700            // schema String
701            0x28, 0x75, 0x36, 0x34, 0x2c, 0x69, 0x36, 0x34,
702            0x29,
703            // Data: (U64(12), I64(64))
704            0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
705            0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
706        ];
707        let (dir, file) = random_file().unwrap();
708        std::fs::write(dir.path().join("demo.ts"), &blob).is_ok();
709
710        let mut s = Storage::open(file).unwrap();
711        println!("{:?}", s);
712
713        let mut t = Tuple { data: vec![ U64(12), I64(64) ]};
714        assert_eq!(Ok(1), s.update(&mut t));
715        s.persist().unwrap();
716
717        let r = std::fs::read(dir.path().join("demo.ts")).unwrap();
718        assert_eq!(expected, r, "\n  expected: `{:x?}`\n  read:     `{:x?}`", expected, r);
719
720        let mut it = s.iter();
721        assert_eq!(Some(t), it.next());
722        assert_eq!(None, it.next());
723    }
724
725    #[test]
726    fn insert_duplicate() {
727        let schema = "(u8, i8)";
728        let (_dir, file) = random_file().unwrap();
729        let mut s = Storage::create(file, schema).unwrap();
730
731        let mut t = Tuple { data: vec![ U8(12), I8(64) ]};
732
733        assert_eq!(Ok(()), s.insert(&mut t));
734        assert_eq!(1, s.header.n_tuples);
735
736        assert_eq!(Err(SchemaError::DuplicateKey), s.insert(&mut t));
737        assert_eq!(1, s.header.n_tuples);
738    }
739
740    #[test]
741    fn insert_sorted() {
742        let schema = "(u8, i8)";
743        let (_dir, file) = random_file().unwrap();
744        let mut s = Storage::create(file, schema).unwrap();
745
746        let mut t0 = Tuple { data: vec![ U8(12), I8(64) ]};
747        assert_eq!(Ok(()), s.insert(&mut t0));
748        assert_eq!(1, s.header.n_tuples);
749
750        let mut t1 = Tuple { data: vec![ U8(8), I8(64) ]};
751        assert_eq!(Ok(()), s.insert(&mut t1));
752        assert_eq!(2, s.header.n_tuples);
753
754        let mut t2 = Tuple { data: vec![ U8(6), I8(64) ]};
755        assert_eq!(Ok(()), s.insert(&mut t2));
756        assert_eq!(3, s.header.n_tuples);
757
758        let mut iter = s.iter();
759        assert_eq!(Some(t2), iter.next(), "t2");
760        assert_eq!(Some(t1), iter.next(), "t1");
761        assert_eq!(Some(t0), iter.next(), "t0");
762    }
763
764    #[test]
765    fn remove_all() {
766        let schema = "(u8, i8)";
767        let (_dir, file) = random_file().unwrap();
768        let mut s = Storage::create(file, schema).unwrap();
769
770        let mut t0 = Tuple { data: vec![ U8(12), I8(64) ]};
771        assert_eq!(Ok(()), s.insert(&mut t0));
772
773        let mut t1 = Tuple { data: vec![ U8(8), I8(64) ]};
774        assert_eq!(Ok(()), s.insert(&mut t1));
775
776        let filter = Filter::Equal(U8(12));
777        assert_eq!(1, s.remove_all(&filter));
778        assert_eq!(1, s.header.n_tuples);
779
780        let mut iter = s.iter();
781        assert_eq!(Some(t1), iter.next(), "t1");
782        assert_eq!(None, iter.next(), "should be empty");
783    }
784
785    #[test]
786    fn remove_mid() {
787        let schema = "(u8, i8)";
788        let (_dir, file) = random_file().unwrap();
789        let mut s = Storage::create(file, schema).unwrap();
790
791        let mut t0 = Tuple { data: vec![ U8(12), I8(64) ]};
792        assert_eq!(Ok(()), s.insert(&mut t0));
793
794        let mut t1 = Tuple { data: vec![ U8(8), I8(64) ]};
795        assert_eq!(Ok(()), s.insert(&mut t1));
796
797        let mut t2 = Tuple { data: vec![ U8(6), I8(64) ]};
798        assert_eq!(Ok(()), s.insert(&mut t2));
799
800        let filter = Filter::Equal(U8(8));
801        assert_eq!(1, s.remove(&filter));
802        assert_eq!(2, s.header.n_tuples);
803
804        let mut iter = s.iter();
805        assert_eq!(Some(t2), iter.next(), "t2");
806        assert_eq!(Some(t0), iter.next(), "t0");
807        assert_eq!(None, iter.next(), "should be empty");
808    }
809
810    #[test]
811    fn remove_first() {
812        let schema = "(u8, i8)";
813        let (_dir, file) = random_file().unwrap();
814        let mut s = Storage::create(file, schema).unwrap();
815
816        let mut t0 = Tuple { data: vec![ U8(12), I8(0) ]};
817        assert_eq!(Ok(()), s.insert(&mut t0));
818
819        let mut t1 = Tuple { data: vec![ U8(8), I8(1) ]};
820        assert_eq!(Ok(()), s.insert(&mut t1));
821
822        let mut t2 = Tuple { data: vec![ U8(6), I8(2) ]};
823        assert_eq!(Ok(()), s.insert(&mut t2));
824
825        let filter = Filter::Less(U8(8));
826        assert_eq!(1, s.remove(&filter));
827        assert_eq!(2, s.header.n_tuples);
828
829        let mut iter = s.iter();
830        assert_eq!(Some(t1), iter.next(), "t1");
831        assert_eq!(Some(t0), iter.next(), "t0");
832        assert_eq!(None, iter.next(), "should be empty");
833    }
834
835    #[test]
836    fn remove_sorted_all() {
837        let schema = "(i8, i8)";
838        let (_dir, file) = random_file().unwrap();
839        let mut s = Storage::create(file, schema).unwrap();
840
841        let mut t0 = Tuple { data: vec![ I8(2), I8(0) ]};
842        assert_eq!(Ok(()), s.insert(&mut t0));
843
844        let mut t1 = Tuple { data: vec![ I8(0), I8(1) ]};
845        assert_eq!(Ok(()), s.insert(&mut t1));
846
847        let mut t2 = Tuple { data: vec![ I8(-1), I8(2) ]};
848        assert_eq!(Ok(()), s.insert(&mut t2));
849
850        let filter = Filter::Greater(I8(-10));
851        assert_eq!(3, s.remove(&filter));
852        assert_eq!(0, s.header.n_tuples);
853
854        let mut iter = s.iter();
855        assert_eq!(None, iter.next(), "should be empty");
856    }
857
858
859
860    #[test]
861    fn schema_to_string() {
862        let schema = "(i8, i8)";
863        let (_dir, file) = random_file().unwrap();
864        let s = Storage::create(file, schema).unwrap();
865
866        assert_eq!(schema, s.schema_to_string());
867    }
868
869    #[test]
870    fn tuple_to_string() {
871        let expected = "(-666, 747)";
872        let t = Tuple { data: vec![ I32(-666), U16(747) ] };
873
874        assert_eq!(expected, t.to_string())
875    }
876}