persistent_array/
lib.rs

1// Copyright (c) 2016 Jonathan Nilsson
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9extern crate layout_id;
10extern crate memmap;
11
12use layout_id::layout_id;
13use memmap::MmapMut;
14use memmap::MmapOptions;
15use std::default::Default;
16use std::fs::OpenOptions;
17use std::io;
18use std::marker::PhantomData;
19use std::mem::{size_of, transmute};
20use std::ops::{Deref, DerefMut};
21use std::path::Path;
22use std::slice;
23
24const MAGIC_BYTES: &'static [u8; 4] = b"PADB";
25
26#[derive(Debug)]
27pub enum Error {
28    UnableToOpenFile(io::Error),
29    WrongMagicBytes,
30    WrongFileSize,
31    WrongTypeId,
32}
33
34/// Persistent Array
35///
36/// A memory mapped array that can be used as a slice.
37pub struct PersistentArray<T: Copy> {
38    phantom_type: PhantomData<T>,
39    map: MmapMut,
40    elements: u64,
41}
42
43#[repr(C, packed)]
44struct Header {
45    magic: [u8; 4],
46    size: u64,
47    typeid: u64,
48}
49
50impl<T: Copy + Default> PersistentArray<T> {
51    /// Creates a new persistent array
52    pub fn new<P>(path: P, size: u64) -> Result<PersistentArray<T>, Error>
53    where
54        P: AsRef<Path>,
55    {
56        let file = match OpenOptions::new()
57            .read(true)
58            .write(true)
59            .create(true)
60            .open(&path)
61        {
62            Ok(file) => file,
63            Err(err) => return Err(Error::UnableToOpenFile(err)),
64        };
65
66        if let Err(err) = file.set_len(size * size_of::<T>() as u64 + size_of::<Header>() as u64) {
67            return Err(Error::UnableToOpenFile(err));
68        }
69
70        println!("{:?}", "Hej");
71
72        let mut map = unsafe {
73            match MmapOptions::new().map_mut(&file) {
74                Ok(map) => map,
75                Err(err) => return Err(Error::UnableToOpenFile(err)),
76            }
77        };
78
79        println!("{:?}", "Hej");
80
81        if map.len() as u64 != size * size_of::<T>() as u64 + size_of::<Header>() as u64 {
82            return Err(Error::WrongFileSize);
83        }
84
85        let header: &mut Header = unsafe { transmute(map.as_mut_ptr()) };
86
87        *header = Header {
88            magic: *MAGIC_BYTES,
89            size: size,
90            typeid: layout_id::<T>(),
91        };
92
93        let element: T = Default::default();
94
95        let elements: &mut [T] = unsafe {
96            slice::from_raw_parts_mut(
97                map.as_mut_ptr().offset(size_of::<Header>() as isize) as *mut T,
98                size as usize,
99            )
100        };
101
102        for e in elements.iter_mut() {
103            *e = element;
104        }
105
106        Ok(PersistentArray {
107            phantom_type: PhantomData,
108            map: map,
109            elements: size,
110        })
111    }
112
113    /// Opens an existing persistent array
114    pub fn open<P>(path: P) -> Result<PersistentArray<T>, Error>
115    where
116        P: AsRef<Path>,
117    {
118        let file = match OpenOptions::new().read(true).write(true).open(&path) {
119            Ok(file) => file,
120            Err(err) => return Err(Error::UnableToOpenFile(err)),
121        };
122
123        let map = unsafe {
124            match MmapOptions::new().map_mut(&file) {
125                Ok(map) => map,
126                Err(err) => return Err(Error::UnableToOpenFile(err)),
127            }
128        };
129
130        let ptr = map.as_ptr();
131        let size = map.len();
132
133        if size < size_of::<Header>() {
134            return Err(Error::WrongFileSize);
135        }
136
137        let header: &Header = unsafe { transmute(ptr) };
138
139        if header.magic != *MAGIC_BYTES {
140            return Err(Error::WrongMagicBytes);
141        }
142
143        let elements = ((size - size_of::<Header>()) / size_of::<T>()) as u64;
144
145        if header.size != elements {
146            return Err(Error::WrongFileSize);
147        }
148
149        if header.typeid != layout_id::<T>() {
150            return Err(Error::WrongTypeId);
151        }
152
153        Ok(PersistentArray {
154            phantom_type: PhantomData,
155            map: map,
156            elements: elements,
157        })
158    }
159}
160
161impl<T: Copy> Deref for PersistentArray<T> {
162    type Target = [T];
163
164    fn deref(&self) -> &[T] {
165        unsafe {
166            slice::from_raw_parts(
167                self.map.as_ptr().offset(size_of::<Header>() as isize) as *const T,
168                self.elements as usize,
169            )
170        }
171    }
172}
173
174impl<T: Copy> DerefMut for PersistentArray<T> {
175    fn deref_mut(&mut self) -> &mut [T] {
176        unsafe {
177            slice::from_raw_parts_mut(
178                self.map.as_mut_ptr().offset(size_of::<Header>() as isize) as *mut T,
179                self.elements as usize,
180            )
181        }
182    }
183}