Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /// This defines a custom Diesel type for storing a 6-bit integer and a 58-bit
- /// integer in the same 64-bit SQL column
- use std::error::Error;
- use std::fmt;
- use std::io::Write;
- use diesel::backend::Backend;
- use diesel::types::{FromSqlRow,FromSql,ToSql,HasSqlType,IsNull,BigInt,Nullable};
- use diesel::expression::AsExpression;
- use diesel::row::Row;
- // store depth in 6 bits + store index in MAX_DEPTH bits = 64
- const COORDINATE_MAX_DEPTH: usize = 58;
- const COORDINATE_INDEX_MASK: u64 = (1u64<<COORDINATE_MAX_DEPTH)-1;
- #[derive(Debug)]
- enum CoordinateError {
- From(i64),
- To(Coordinate),
- }
- impl fmt::Display for CoordinateError {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt,"The value {:?} is not a valid coordinate", self)
- }
- }
- impl Error for CoordinateError {
- fn description(&self) -> &str {
- "The value is not a valid coordinate"
- }
- }
- #[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
- pub struct Coordinate {
- index: u64,
- depth: u8,
- }
- impl Coordinate {
- fn to_i64(&self) -> Result<i64,CoordinateError> {
- if self.depth as usize > COORDINATE_MAX_DEPTH || self.index > COORDINATE_INDEX_MASK {
- Err(CoordinateError::To(*self))
- } else {
- Ok((((self.depth as u64)<<COORDINATE_MAX_DEPTH) | (self.index & COORDINATE_INDEX_MASK)) as i64)
- }
- }
- fn from_i64(i: i64) -> Result<Self,CoordinateError> {
- let depth=((i as u64)>>COORDINATE_MAX_DEPTH) as u8;
- let index=(i as u64)&COORDINATE_INDEX_MASK;
- if depth>58 {
- Err(CoordinateError::From(i))
- } else {
- Ok(Coordinate{depth:depth,index:index})
- }
- }
- }
- impl<DB> FromSqlRow<BigInt, DB> for Coordinate where DB: Backend + HasSqlType<BigInt>, i64: FromSql<BigInt, DB> {
- fn build_from_row<T: Row<DB>>(row: &mut T) -> Result<Self, Box<Error + Send + Sync>> {
- <i64 as FromSqlRow<BigInt, DB>>::build_from_row(row).and_then(|i|Coordinate::from_i64(i).map_err(|e|Box::new(e) as _))
- }
- }
- impl<DB: Backend<RawValue=[u8]>> FromSql<BigInt, DB> for Coordinate {
- fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<Error + Send + Sync>> {
- <i64 as FromSql<_,DB>>::from_sql(bytes).and_then(|i|Coordinate::from_i64(i).map_err(|e|Box::new(e) as _))
- }
- }
- impl<DB: Backend> ToSql<BigInt, DB> for Coordinate {
- fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error + Send + Sync>> {
- let i=try!(self.to_i64().map_err(Box::new));
- <i64 as ToSql<BigInt,DB>>::to_sql(&i, out)
- }
- }
- impl AsExpression<BigInt> for Coordinate {
- type Expression = <i64 as AsExpression<BigInt>>::Expression;
- fn as_expression(self) -> Self::Expression {
- <i64 as AsExpression<BigInt>>::as_expression(self.to_i64().expect("The value is not a valid coordinate"))
- }
- }
- impl<'a> AsExpression<BigInt> for &'a Coordinate {
- type Expression = <i64 as AsExpression<BigInt>>::Expression;
- fn as_expression(self) -> Self::Expression {
- <i64 as AsExpression<BigInt>>::as_expression(self.to_i64().expect("The value is not a valid coordinate"))
- }
- }
- impl AsExpression<Nullable<BigInt>> for Coordinate {
- type Expression = <i64 as AsExpression<Nullable<BigInt>>>::Expression;
- fn as_expression(self) -> Self::Expression {
- <i64 as AsExpression<Nullable<BigInt>>>::as_expression(self.to_i64().expect("The value is not a valid coordinate"))
- }
- }
- impl<'a> AsExpression<Nullable<BigInt>> for &'a Coordinate {
- type Expression = <i64 as AsExpression<Nullable<BigInt>>>::Expression;
- fn as_expression(self) -> Self::Expression {
- <i64 as AsExpression<Nullable<BigInt>>>::as_expression(self.to_i64().expect("The value is not a valid coordinate"))
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement