while moving to storage in pages

This commit is contained in:
Shautvast 2025-02-20 08:37:31 +01:00
parent 3281edc350
commit 68a2224dc7
16 changed files with 355 additions and 203 deletions

View file

@ -1,18 +1,18 @@
use csv::table::Table; use csv::table::Table;
fn main() { // fn main() {
let left = Table::from_csv(include_str!("data/left.csv"), Some("\t")); // let left = Table::from_csv(include_str!("data/left.csv"), Some("\t"));
let right = Table::from_csv(include_str!("data/right.csv"), Some("\t")); // let right = Table::from_csv(include_str!("data/right.csv"), Some("\t"));
println!("left:"); // println!("left:");
left.select("*"); // left.select("*");
println!("\nright:"); // println!("\nright:");
right.select("*"); // right.select("*");
println!("\njoin on name:"); // println!("\njoin on name:");
left.left_join(&right, "name", "name", false) // left.left_join(&right, "name", "name", false)
.select("name, cowdung, value"); // .select("name, cowdung, value");
println!("\nleft join on name:"); // println!("\nleft join on name:");
left.left_join(&right, "name", "name", true).select("*"); // left.left_join(&right, "name", "name", true).select("*");
println!("\nright join on name:"); // println!("\nright join on name:");
left.right_join(&right, "name", "name", true) // left.right_join(&right, "name", "name", true)
.select("name,cowdung,value"); // .select("name,cowdung,value");
} // }

View file

@ -1,12 +1,12 @@
use csv::table::Table; use csv::table::Table;
fn main() { fn main() {
let table = Table::from_csv(include_str!("data/table.csv"), Some("\t")); // let table = Table::from_csv(include_str!("data/table.csv"), Some("\t"));
println!("not ordered:"); // println!("not ordered:");
table.select("*"); // table.select("*");
//
println!("order by name ascending:"); // println!("order by name ascending:");
table.order_by("name").select("*"); // table.order_by("name").select("*");
//
println!("\nTODO descending"); // println!("\nTODO descending");
} }

3
src/data/test.csv Normal file
View file

@ -0,0 +1,3 @@
name value
a 3
b 4
1 name value
2 a 3
3 b 4

18
src/id_sequence.rs Normal file
View file

@ -0,0 +1,18 @@
use std::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug)]
pub struct ThreadSafeIdGenerator {
counter: AtomicUsize,
}
impl ThreadSafeIdGenerator {
pub fn new(start: usize) -> Self {
Self {
counter: AtomicUsize::new(start),
}
}
pub fn next(&self) -> usize {
self.counter.fetch_add(1, Ordering::SeqCst)
}
}

View file

@ -1,29 +1,29 @@
use crate::table::Table; use crate::table::Table;
impl Table { impl Table {
pub fn left_join(&self, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table { // pub fn left_join(&self, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table {
join(self, right, left_col, right_col, outer) // join(self, right, left_col, right_col, outer)
// }
//
// pub fn right_join(&self, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table {
// join(right, self, right_col, left_col, outer)
// }
} }
pub fn right_join(&self, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table { // pub fn join(left: &Table, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table {
join(right, self, right_col, left_col, outer) // let mut joined = Table::new("join");
} // left.cols.iter().for_each(|c| joined.add_column(c, true));
} // right.cols.iter().for_each(|c| joined.add_column(c, true));
// let left_col_index = left.get_index(left_col);
pub fn join(left: &Table, right: &Table, left_col: &str, right_col: &str, outer: bool) -> Table { // let right_col_index = right.get_index(right_col);
let mut joined = Table::new("join"); //
left.cols.iter().for_each(|c| joined.add_column(c, true)); // for record in left.iter_records() {
right.cols.iter().for_each(|c| joined.add_column(c, true)); // let lv = record.get(left_col_index);
let left_col_index = left.get_index(left_col); // if let Some(right_record) = right.where_clause(right_col_index, lv) {
let right_col_index = right.get_index(right_col); // joined.add_record(record + right_record);
// } else if outer {
for record in left.iter_records() { // joined.add_record(record.clone());
let lv = record.get(left_col_index); // }
if let Some(right_record) = right.where_clause(right_col_index, lv) { // }
joined.add_record(record + right_record); // joined
} else if outer { // }
joined.add_record(record.clone());
}
}
joined
}

View file

@ -9,3 +9,5 @@ pub mod table;
pub mod value; pub mod value;
mod varint; mod varint;
pub mod vm; pub mod vm;
mod id_sequence;
mod record;

View file

@ -1,7 +1,8 @@
use csv::table::Table; use csv::table::Table;
fn main() { fn main() {
let csv = include_str!("data/portfolios.csv"); let csv = include_str!("data/test.csv");
let table = Table::from_csv(csv, None); let table = Table::from_csv(csv, None);
table.order_by("name").select("*"); println!("{:?}",table);
table.select("*");
} }

View file

@ -3,17 +3,17 @@ use std::collections::BTreeMap;
use crate::table::{Key, Table}; use crate::table::{Key, Table};
impl Table { impl Table {
pub fn order_by(&self, expression: &str) -> Self { // pub fn order_by(&self, expression: &str) -> Self {
let indexes = self.get_column_indexes(expression); // let indexes = self.get_column_indexes(expression);
if self.views.contains_key(expression) {} // if self.views.contains_key(expression) {}
//
let mut sorted_records = BTreeMap::new(); // let mut sorted_records = BTreeMap::new();
for record in self.iter() { // for record in self.iter() {
let key = indexes.iter().map(|i| record.get(*i).clone()).collect(); // let key = indexes.iter().map(|i| record.get(*i).clone()).collect();
sorted_records.insert(Key::compound(key), record.clone()); // sorted_records.insert(Key::compound(key), record.clone());
} // }
let mut ordered = Table::empty_copy(self); // let mut ordered = Table::empty_copy(self);
ordered.records = sorted_records; // ordered.records = sorted_records;
ordered // ordered
} // }
} }

View file

@ -1,71 +1,86 @@
use std::ops::Add; use crate::record::Record;
use crate::value::Value;
use crate::value::{Value, NULL}; use crate::varint;
use byteorder::{BigEndian, ByteOrder};
const PAGE_SIZE: usize = 4096; const PAGE_SIZE: usize = 4096;
#[derive(Debug)]
pub enum PageType { pub enum PageType {
Root, Root,
Interior, Interior,
Leaf, Leaf,
} }
#[derive(Debug)]
pub struct Page { pub struct Page {
pagetype: PageType, pagetype: PageType,
id: usize,
start: Value,
end: Value,
data: Vec<u8>, data: Vec<u8>,
index_pos: u16, index_pos: u16,
data_pos: u16, data_pos: u16,
key: usize, key: usize,
children: Vec<Page>, children: Vec<Page>,
n_records: usize,
} }
impl Page { impl Page {
pub fn new(pagetype: PageType) -> Self { pub fn new(pagetype: PageType, id: usize) -> Self {
Self { Self {
pagetype, pagetype,
id,
start: Value::null(),
end: Value::null(),
data: vec![0; PAGE_SIZE], data: vec![0; PAGE_SIZE],
index_pos: 0, index_pos: 0,
data_pos: (PAGE_SIZE - 1) as u16, data_pos: (PAGE_SIZE - 1) as u16,
key: 0, key: 0,
children: vec![], children: vec![],
n_records: 0,
} }
} }
pub fn add_record(&mut self, record: Record) {} pub fn insert(&mut self, record: Record) {
let bytes: Vec<u8> = record.into();
self.insert_data(bytes);
self.insert_index(self.data_pos);
self.n_records += 1;
} }
#[derive(Debug, Clone)] fn insert_data(&mut self, bytes: Vec<u8>) {
pub struct Record { let end = self.data_pos as usize;
values: Vec<Value>, self.data_pos -= bytes.len() as u16;
self.data.splice(self.data_pos as usize..end, bytes);
} }
impl Record { fn insert_index(&mut self, value: u16) {
pub fn string_len(&self) -> usize { let bytes = u16_to_bytes(value);
self.values.iter().map(Value::string_len).sum() let start = self.index_pos as usize;
self.index_pos += bytes.len() as u16;
self.data.splice(start..self.index_pos as usize, bytes);
} }
pub fn add_value(&mut self, value: impl Into<Value>) { pub fn get(&self, index: usize) -> Option<Record> {
self.values.push(value.into()); if index < self.n_records {
let index = BigEndian::read_u16(&self.data[index * 2..=index * 2 + 1]);
let (nbytes, len) = varint::read(&self.data[index as usize..]);
Some(
(
len,
&self.data[nbytes + index as usize..nbytes + index as usize + len as usize],
)
.into(),
)
} else {
None
} }
pub fn get(&self, index: usize) -> Value {
self.values.get(index).map(|v| v.clone()).unwrap_or(NULL)
} }
} }
impl Add for &Record { fn u16_to_bytes(value: u16) -> Vec<u8> {
type Output = Record; let mut buf = vec![0; 2];
BigEndian::write_u16(&mut buf, value);
fn add(self, rhs: Self) -> Self::Output { buf
let mut sum = Record::default();
sum.values.append(&mut self.values.clone());
sum.values.append(&mut rhs.values.clone()); // use refs?
sum
}
}
impl Default for Record {
fn default() -> Self {
Self { values: vec![] }
}
} }

View file

@ -27,7 +27,7 @@ impl Table {
print!("| {:<w$} ", col); print!("| {:<w$} ", col);
} }
println!("|"); println!("|");
for record in self.iter_records() { for record in self.iter() {
for col in self.iter_colums() { for col in self.iter_colums() {
let w = column_widths.get(col).unwrap_or(&0); let w = column_widths.get(col).unwrap_or(&0);
// eprintln!("{}", w); // eprintln!("{}", w);
@ -45,7 +45,7 @@ impl Table {
print!("| {:<w$} ", col); print!("| {:<w$} ", col);
} }
println!("|"); println!("|");
for record in self.iter_records() { for record in self.iter() {
for col in self.select_columns(&columns) { for col in self.select_columns(&columns) {
let w = column_widths.get(col).unwrap_or(&0); let w = column_widths.get(col).unwrap_or(&0);
// eprintln!("{}", w); // eprintln!("{}", w);
@ -66,7 +66,7 @@ impl Table {
for col in self.iter_colums() { for col in self.iter_colums() {
widths.insert(col, col.len()); widths.insert(col, col.len());
} }
for record in self.iter_records().skip(offset).take(nrecords) { for record in self.iter().skip(offset).take(nrecords) {
for col in self.iter_colums() { for col in self.iter_colums() {
let e = widths.get_mut(&col).unwrap(); let e = widths.get_mut(&col).unwrap();
let index = self.get_index(col); let index = self.get_index(col);
@ -92,7 +92,7 @@ impl Table {
for col in self.select_columns(columns) { for col in self.select_columns(columns) {
widths.insert(col, col.len()); widths.insert(col, col.len());
} }
for record in self.iter_records().skip(offset).take(nrecords) { for record in self.iter().skip(offset).take(nrecords) {
for col in self.select_columns(columns) { for col in self.select_columns(columns) {
let e = widths.get_mut(&col).unwrap(); let e = widths.get_mut(&col).unwrap();
let index = self.get_index(&col); let index = self.get_index(&col);

View file

@ -1,5 +1,7 @@
use crate::table::{Record, Table}; use crate::table::Table;
use std::fs; use std::fs;
use crate::record::Record;
const EOL: &str = "\n"; const EOL: &str = "\n";

141
src/record.rs Normal file
View file

@ -0,0 +1,141 @@
use crate::value::Value;
use crate::varint;
use byteorder::{BigEndian, ByteOrder};
use std::ops::Add;
#[derive(Debug, Clone)]
pub struct Record {
pub rowid: u64,
pub(crate) values: Vec<Value>,
}
impl Record {
pub fn string_len(&self) -> usize {
self.values.iter().map(Value::string_len).sum()
}
pub fn bytes_len(&self) -> u16 {
let record_length: u16 = self.values.iter().map(Value::bytes_len).sum();
record_length + 1
}
pub fn add_value(&mut self, value: impl Into<Value>) {
self.values.push(value.into());
}
pub fn get(&self, index: usize) -> &Value {
self.values.get(index).unwrap() //TODO
}
}
impl Add for &Record {
type Output = Record;
fn add(self, rhs: Self) -> Self::Output {
let mut sum = Record::default();
sum.values.append(&mut self.values.clone());
sum.values.append(&mut rhs.values.clone()); // use refs?
sum
}
}
impl From<Record> for Vec<u8> {
fn from(mut record: Record) -> Vec<u8> {
let record_length = record.bytes_len();
let mut length_bytes = varint::write(u64::from(record_length));
let mut rowid_bytes = varint::write(record.rowid);
let mut buffer =
Vec::with_capacity(length_bytes.len() + rowid_bytes.len() + record_length as usize);
buffer.append(&mut length_bytes);
buffer.append(&mut rowid_bytes);
// 'The initial portion of the payload that does not spill to overflow pages.'
let length_of_encoded_column_types: usize =
record.values.iter().map(|v| v.datatype_bytes.len()).sum();
buffer.append(&mut varint::write(
(length_of_encoded_column_types + 1) as u64,
));
//write all types
for v in &mut record.values {
buffer.append(&mut v.datatype_bytes);
}
// write all values
for v in &mut record.values {
buffer.append(&mut v.data);
}
buffer
}
}
impl Into<Record> for (u64, &[u8]) {
fn into(self) -> Record {
let (len, data) = self;
let len = len as usize; //meh
let (mut offset, rowid) = varint::read(data);
let mut datatypes = vec![];
//read n of fields
while (offset < len) {
let (inc, datatype) = varint::read(&data[offset..]);
datatypes.push(datatype);
offset += inc;
}
let mut values: Vec<Value> = vec![];
for dt in datatypes {
match dt {
13.. if dt % 2 == 0 => {
let len = ((dt >> 1) - 13) as usize;
if let Ok(text) = String::from_utf8(data[offset..len].to_vec()) {
values.push(text.into());
}
offset += len;
}
12.. if dt % 2 == 0 => {
let len = ((dt >> 1) - 12) as usize;
// no blobs yet
offset += len;
}
9 => values.push(1.into()),
8 => values.push(0.into()),
7 => {
values.push(BigEndian::read_f64(&data[offset..offset + 8]).into());
offset += 8;
}
1..=6 => {
let (inc, v) = read_int(&data[offset..], dt);
values.push(v.into());
offset += inc;
}
0 => {
values.push(Value::null());
}
_ => panic!("unknown datatype"),
}
}
Record { rowid, values }
}
}
fn read_int(buf: &[u8], datatype: u64) -> (usize, i64) {
let nb = match datatype {
6 => 8,
5 => 6,
_ => datatype as usize,
};
(nb, BigEndian::read_i64(&buf[..nb]))
}
impl Default for Record {
fn default() -> Self {
Self {
rowid: 0,
values: vec![],
}
}
}

View file

@ -2,7 +2,7 @@ use std::collections::HashMap;
use anyhow::anyhow; use anyhow::anyhow;
use crate::value::{Value, NULL}; use crate::value::Value;
use super::tokens::{Token, TokenType}; use super::tokens::{Token, TokenType};
@ -154,7 +154,7 @@ impl Scanner {
fn add_token(&mut self, tokentype: TokenType) { fn add_token(&mut self, tokentype: TokenType) {
let text = self.source[self.start..self.current].to_string(); let text = self.source[self.start..self.current].to_string();
self.tokens.push(Token::new(tokentype, text, NULL)); self.tokens.push(Token::new(tokentype, text, Value::null()));
} }
fn add_literal(&mut self, tokentype: TokenType, literal: Value) { fn add_literal(&mut self, tokentype: TokenType, literal: Value) {

View file

@ -1,32 +1,43 @@
use crate::id_sequence::ThreadSafeIdGenerator;
use crate::page::{Page, PageType};
use crate::record::Record;
use crate::value::Value;
use std::cell::RefCell;
use std::rc::Rc;
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap}
iter::Map,
ops::Add,
}; };
use crate::value::Value; #[derive(Debug)]
pub struct View { pub struct View {
records: BTreeMap<Key, Key>, records: BTreeMap<Key, Key>,
} }
#[derive(Debug)]
pub struct Table { pub struct Table {
name: String, name: String,
cols_by_name: HashMap<String, usize>, cols_by_name: HashMap<String, usize>,
pub(crate) cols: Vec<String>, pub(crate) cols: Vec<String>,
pub(crate) records: BTreeMap<Key, Record>, pub(crate) root: Rc<RefCell<Page>>,
pub views: HashMap<String, View>, pub views: HashMap<String, View>,
page_ids: ThreadSafeIdGenerator,
row_ids: ThreadSafeIdGenerator,
current_page: Rc<RefCell<Page>>,
} }
impl Table { impl Table {
pub fn new(name: impl Into<String>) -> Self { pub fn new(name: impl Into<String>) -> Self {
let root = Rc::new(RefCell::new(Page::new(PageType::Root, 0)));
Self { Self {
name: name.into(), name: name.into(),
cols_by_name: HashMap::new(), cols_by_name: HashMap::new(),
cols: vec![], cols: vec![],
records: BTreeMap::new(), root: Rc::clone(&root),
views: HashMap::new(), views: HashMap::new(),
page_ids: ThreadSafeIdGenerator::new(1),
row_ids: ThreadSafeIdGenerator::new(0),
current_page: root,
} }
} }
@ -42,8 +53,7 @@ impl Table {
} }
pub fn add_record(&mut self, record: Record) { pub fn add_record(&mut self, record: Record) {
let index = self.records.len(); self.current_page.borrow_mut().insert(record);
self.records.insert(Key::integer(index), record);
} }
pub fn has_column(&self, name: impl Into<String>) -> bool { pub fn has_column(&self, name: impl Into<String>) -> bool {
@ -85,12 +95,9 @@ impl Table {
} }
pub fn iter(&self) -> TableIter { pub fn iter(&self) -> TableIter {
self.iter_records()
}
pub fn iter_records(&self) -> TableIter {
TableIter { TableIter {
table_iter: self.records.iter(), rootPage: Rc::clone(&self.root),
index: 0,
} }
} }
@ -108,69 +115,27 @@ impl Table {
} }
} }
pub fn where_clause(&self, colindex: usize, value: &Value) -> Option<&Record> { // pub fn where_clause(&self, colindex: usize, value: &Value) -> Option<&Record> {
for record in self.iter_records() { // for record in self.iter() {
let r = record.get(colindex); // let r = record.get(colindex);
if r == value { // if r == value {
return Some(record); // return Some(record);
} // }
} // }
None // None
} // }
} }
#[derive(Debug, Clone)] pub struct TableIter {
pub struct Record { rootPage: Rc<RefCell<Page>>,
values: Vec<Value>, index: usize,
} }
impl Record { impl Iterator for TableIter {
pub fn string_len(&self) -> usize { type Item = Record;
self.values.iter().map(Value::string_len).sum()
}
pub fn add_value(&mut self, value: impl Into<Value>) {
self.values.push(value.into());
}
pub fn get(&self, index: usize) -> &Value {
self.values.get(index).unwrap() //TODO
}
}
impl Add for &Record {
type Output = Record;
fn add(self, rhs: Self) -> Self::Output {
let mut sum = Record::default();
sum.values.append(&mut self.values.clone());
sum.values.append(&mut rhs.values.clone()); // use refs?
sum
}
}
impl Default for Record {
fn default() -> Self {
Self { values: vec![] }
}
}
pub struct TableIter<'a> {
table_iter: std::collections::btree_map::Iter<'a, Key, Record>,
}
pub struct ViewIter<'a> {
iter: Map<
std::collections::btree_map::Iter<'a, Key, Key>,
Box<dyn Fn((&'a Key, &'a Key)) -> Option<&'a Record>>,
>,
}
impl<'a> Iterator for TableIter<'a> {
type Item = &'a Record;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.table_iter.next().map(|e| e.1) self.rootPage.borrow().get(self.index)
} }
} }

View file

@ -2,13 +2,13 @@ use std::{cmp::Ordering, fmt::Display};
use anyhow::anyhow; use anyhow::anyhow;
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use crate::varint;
pub const NULL: Value = Value::null();
#[derive(Debug, Clone, PartialEq, Eq, Ord)] #[derive(Debug, Clone, PartialEq, Eq, Ord)]
pub struct Value { pub struct Value {
datatype: u64, pub(crate) datatype: u64,
data: Vec<u8>, pub(crate) datatype_bytes: Vec<u8>,
pub(crate) data: Vec<u8>,
} }
impl PartialOrd for Value { impl PartialOrd for Value {
@ -61,21 +61,26 @@ pub enum Datatype {
} }
impl Value { impl Value {
pub const fn null() -> Self { fn new(datatype: u64, data: Vec<u8>) -> Self {
// NULL
Self { Self {
data: vec![], datatype,
datatype: 0, data,
datatype_bytes: varint::write(datatype),
} }
} }
pub fn bytes_len(&self) -> u16 {
(self.datatype_bytes.len() + self.data.len()) as u16
}
pub fn null() -> Self {
Self::new(0 ,vec![])
}
pub fn from_f64(value: f64) -> Self { pub fn from_f64(value: f64) -> Self {
let mut buf = vec![0; 8]; let mut buf = vec![0; 8];
BigEndian::write_f64(&mut buf, value); BigEndian::write_f64(&mut buf, value);
Self { Self::new(7, buf)
datatype: 7,
data: buf,
}
} }
pub fn from_i64(value: i64) -> Self { pub fn from_i64(value: i64) -> Self {
@ -87,14 +92,14 @@ impl Value {
(int_datatype(data.len()), data) (int_datatype(data.len()), data)
} }
}; };
Self { datatype, data } Self::new(datatype,data)
} }
pub fn from_text(value: impl Into<String>) -> Self { pub fn from_text(value: impl Into<String>) -> Self {
let value: String = value.into(); let value: String = value.into();
let datatype = (13 + value.len() * 2) as u64; let datatype = (13 + value.len() * 2) as u64;
let data = value.as_bytes().to_vec(); let data = value.as_bytes().to_vec();
Self { datatype, data } Self::new(datatype,data)
} }
pub fn datatype(&self) -> anyhow::Result<Datatype> { pub fn datatype(&self) -> anyhow::Result<Datatype> {

View file

@ -3,7 +3,7 @@ const SLOT_4_2_0: u64 = 0xf01fc07f;
/// varints as implemented in `SQLite` /// varints as implemented in `SQLite`
pub fn write(value: i64) -> Vec<u8> { pub fn write(value: u64) -> Vec<u8> {
let mut v = value; let mut v = value;
if (v & ((0xff00_0000) << 32)) == 0 { if (v & ((0xff00_0000) << 32)) == 0 {
if v == 0 { if v == 0 {
@ -30,15 +30,15 @@ pub fn write(value: i64) -> Vec<u8> {
} }
} }
pub fn read(data: Vec<u8>) -> u64 { pub fn read(data: &[u8]) -> (usize, u64) {
let mut a = data[0] as u64; let mut a = data[0] as u64;
if (data[0] as i8) >= 0 { if (data[0] as i8) >= 0 {
return a; return (1,a);
} }
let mut b = data[1] as u64; let mut b = data[1] as u64;
if (b & 0x80) == 0 { if (b & 0x80) == 0 {
return ((a & 0x7f) << 7) | b; return (2,((a & 0x7f) << 7) | b);
} }
a = (a << 14) | data[2] as u64; a = (a << 14) | data[2] as u64;
@ -46,7 +46,7 @@ pub fn read(data: Vec<u8>) -> u64 {
a &= SLOT_2_0; a &= SLOT_2_0;
b = (b & 0x7f) << 7; b = (b & 0x7f) << 7;
a |= b; a |= b;
return a; return (3,a);
} }
a &= SLOT_2_0; a &= SLOT_2_0;
@ -55,7 +55,7 @@ pub fn read(data: Vec<u8>) -> u64 {
if (b & 0x80) == 0 { if (b & 0x80) == 0 {
b &= SLOT_2_0; b &= SLOT_2_0;
a = (a << 7) | b; a = (a << 7) | b;
return a; return (4,a);
} }
b &= SLOT_2_0; b &= SLOT_2_0;
@ -67,7 +67,7 @@ pub fn read(data: Vec<u8>) -> u64 {
b = b << 7; b = b << 7;
a |= b; a |= b;
s = s >> 18; s = s >> 18;
return (s << 32) | a; return (5,(s << 32) | a);
} }
s = (s << 7) | b; s = (s << 7) | b;
@ -76,7 +76,7 @@ pub fn read(data: Vec<u8>) -> u64 {
a &= SLOT_2_0; a &= SLOT_2_0;
a = (a << 7) | b; a = (a << 7) | b;
s = s >> 18; s = s >> 18;
return (s << 32) | a; return (6,(s << 32) | a);
} }
a = a << 14; a = a << 14;
@ -87,7 +87,7 @@ pub fn read(data: Vec<u8>) -> u64 {
b = b << 7; b = b << 7;
a |= b; a |= b;
s = s >> 11; s = s >> 11;
return (s << 32) | a; return (7,(s << 32) | a);
} }
a &= SLOT_2_0; a &= SLOT_2_0;
@ -96,7 +96,7 @@ pub fn read(data: Vec<u8>) -> u64 {
b &= SLOT_4_2_0; b &= SLOT_4_2_0;
a = (a << 7) | b; a = (a << 7) | b;
s = s >> 14; s = s >> 14;
return (s << 32) | a; return (8,(s << 32) | a);
} }
a = a << 15; a = a << 15;
@ -109,7 +109,7 @@ pub fn read(data: Vec<u8>) -> u64 {
b &= 0x7f; b &= 0x7f;
b = b >> 3; b = b >> 3;
s |= b; s |= b;
(s << 32) | a (9,(s << 32) | a)
} }
#[cfg(test)] #[cfg(test)]
@ -118,15 +118,15 @@ mod test {
#[test] #[test]
fn test_0() { fn test_0() {
assert_eq!(0, read(write(0))); assert_eq!(0, read(&write(0)).1);
} }
#[test] #[test]
fn test_127() { fn test_127() {
assert_eq!(127, read(write(127))); assert_eq!(127, read(&write(127)).1);
} }
#[test] #[test]
fn test_m127() { fn test_m127() {
assert_eq!(398639861, read(write(398639861))); assert_eq!(398639861, read(&write(398639861)).1);
} }
} }