Advertisement
Guest User

Untitled

a guest
Dec 8th, 2016
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.66 KB | None | 0 0
  1. /// This defines a custom Diesel type for storing a 6-bit integer and a 58-bit
  2. /// integer in the same 64-bit SQL column
  3.  
  4. use std::error::Error;
  5. use std::fmt;
  6. use std::io::Write;
  7. use diesel::backend::Backend;
  8. use diesel::types::{FromSqlRow,FromSql,ToSql,HasSqlType,IsNull,BigInt,Nullable};
  9. use diesel::expression::AsExpression;
  10. use diesel::row::Row;
  11.  
  12. // store depth in 6 bits + store index in MAX_DEPTH bits = 64
  13. const COORDINATE_MAX_DEPTH: usize = 58;
  14. const COORDINATE_INDEX_MASK: u64 = (1u64<<COORDINATE_MAX_DEPTH)-1;
  15.  
  16. #[derive(Debug)]
  17. enum CoordinateError {
  18. From(i64),
  19. To(Coordinate),
  20. }
  21.  
  22. impl fmt::Display for CoordinateError {
  23. fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
  24. write!(fmt,"The value {:?} is not a valid coordinate", self)
  25. }
  26. }
  27.  
  28. impl Error for CoordinateError {
  29. fn description(&self) -> &str {
  30. "The value is not a valid coordinate"
  31. }
  32. }
  33.  
  34. #[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
  35. pub struct Coordinate {
  36. index: u64,
  37. depth: u8,
  38. }
  39.  
  40. impl Coordinate {
  41. fn to_i64(&self) -> Result<i64,CoordinateError> {
  42. if self.depth as usize > COORDINATE_MAX_DEPTH || self.index > COORDINATE_INDEX_MASK {
  43. Err(CoordinateError::To(*self))
  44. } else {
  45. Ok((((self.depth as u64)<<COORDINATE_MAX_DEPTH) | (self.index & COORDINATE_INDEX_MASK)) as i64)
  46. }
  47. }
  48.  
  49. fn from_i64(i: i64) -> Result<Self,CoordinateError> {
  50. let depth=((i as u64)>>COORDINATE_MAX_DEPTH) as u8;
  51. let index=(i as u64)&COORDINATE_INDEX_MASK;
  52. if depth>58 {
  53. Err(CoordinateError::From(i))
  54. } else {
  55. Ok(Coordinate{depth:depth,index:index})
  56. }
  57. }
  58. }
  59.  
  60. impl<DB> FromSqlRow<BigInt, DB> for Coordinate where DB: Backend + HasSqlType<BigInt>, i64: FromSql<BigInt, DB> {
  61. fn build_from_row<T: Row<DB>>(row: &mut T) -> Result<Self, Box<Error + Send + Sync>> {
  62. <i64 as FromSqlRow<BigInt, DB>>::build_from_row(row).and_then(|i|Coordinate::from_i64(i).map_err(|e|Box::new(e) as _))
  63. }
  64. }
  65.  
  66. impl<DB: Backend<RawValue=[u8]>> FromSql<BigInt, DB> for Coordinate {
  67. fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<Error + Send + Sync>> {
  68. <i64 as FromSql<_,DB>>::from_sql(bytes).and_then(|i|Coordinate::from_i64(i).map_err(|e|Box::new(e) as _))
  69. }
  70. }
  71.  
  72. impl<DB: Backend> ToSql<BigInt, DB> for Coordinate {
  73. fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error + Send + Sync>> {
  74. let i=try!(self.to_i64().map_err(Box::new));
  75. <i64 as ToSql<BigInt,DB>>::to_sql(&i, out)
  76. }
  77. }
  78.  
  79. impl AsExpression<BigInt> for Coordinate {
  80. type Expression = <i64 as AsExpression<BigInt>>::Expression;
  81. fn as_expression(self) -> Self::Expression {
  82. <i64 as AsExpression<BigInt>>::as_expression(self.to_i64().expect("The value is not a valid coordinate"))
  83. }
  84. }
  85.  
  86. impl<'a> AsExpression<BigInt> for &'a Coordinate {
  87. type Expression = <i64 as AsExpression<BigInt>>::Expression;
  88. fn as_expression(self) -> Self::Expression {
  89. <i64 as AsExpression<BigInt>>::as_expression(self.to_i64().expect("The value is not a valid coordinate"))
  90. }
  91. }
  92.  
  93. impl AsExpression<Nullable<BigInt>> for Coordinate {
  94. type Expression = <i64 as AsExpression<Nullable<BigInt>>>::Expression;
  95. fn as_expression(self) -> Self::Expression {
  96. <i64 as AsExpression<Nullable<BigInt>>>::as_expression(self.to_i64().expect("The value is not a valid coordinate"))
  97. }
  98. }
  99.  
  100. impl<'a> AsExpression<Nullable<BigInt>> for &'a Coordinate {
  101. type Expression = <i64 as AsExpression<Nullable<BigInt>>>::Expression;
  102. fn as_expression(self) -> Self::Expression {
  103. <i64 as AsExpression<Nullable<BigInt>>>::as_expression(self.to_i64().expect("The value is not a valid coordinate"))
  104. }
  105. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement