use std::cmp;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops;
use crate::traits::{LmdbOrdKey, LmdbOrdKeyIfUnaligned, LmdbRaw, LmdbRawIfUnaligned};
#[repr(C, packed)]
pub struct Unaligned<T: LmdbRawIfUnaligned>(T);
impl<T: LmdbRawIfUnaligned> Clone for Unaligned<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: LmdbRawIfUnaligned> Copy for Unaligned<T> {}
unsafe impl<T: LmdbRawIfUnaligned> LmdbRaw for Unaligned<T> {
fn reported_type() -> String {
format!("Unaligned<{}>", T::reported_type())
}
}
unsafe impl<T: LmdbRawIfUnaligned + LmdbOrdKeyIfUnaligned> LmdbOrdKey for Unaligned<T> {
fn ordered_by_bytes() -> bool {
T::ordered_by_bytes()
}
fn ordered_as_integer() -> bool {
T::ordered_as_integer()
}
}
impl<T: LmdbRawIfUnaligned> Unaligned<T> {
pub fn new(t: T) -> Self {
Unaligned(t)
}
pub fn of_ref(t: &T) -> &Self {
unsafe { &*std::ptr::from_ref::<T>(t).cast::<Unaligned<T>>() }
}
pub fn of_mut(t: &mut T) -> &mut Self {
unsafe { &mut *std::ptr::from_mut::<T>(t).cast::<Unaligned<T>>() }
}
pub fn get(&self) -> T {
self.0
}
pub fn set(&mut self, t: T) {
self.0 = t;
}
}
pub fn unaligned<T: LmdbRawIfUnaligned>(t: &T) -> &Unaligned<T> {
Unaligned::of_ref(t)
}
macro_rules! deleg_fmt {
($tr:ident) => {
impl<T: LmdbRawIfUnaligned> fmt::$tr for Unaligned<T>
where
T: fmt::$tr,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let inner = self.0;
inner.fmt(fmt)
}
}
};
}
deleg_fmt!(Binary);
deleg_fmt!(Debug);
deleg_fmt!(Display);
deleg_fmt!(LowerExp);
deleg_fmt!(LowerHex);
deleg_fmt!(Octal);
deleg_fmt!(Pointer);
deleg_fmt!(UpperExp);
deleg_fmt!(UpperHex);
impl<T: LmdbRawIfUnaligned + PartialEq<T>> PartialEq<Unaligned<T>> for Unaligned<T> {
fn eq(&self, other: &Self) -> bool {
let (lhs, rhs) = (self.0, other.0);
lhs.eq(&rhs)
}
}
impl<T: LmdbRawIfUnaligned + Eq> Eq for Unaligned<T> {}
impl<T: LmdbRawIfUnaligned + PartialOrd<T>> PartialOrd<Unaligned<T>> for Unaligned<T> {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
let (lhs, rhs) = (self.0, other.0);
lhs.partial_cmp(&rhs)
}
fn lt(&self, other: &Self) -> bool {
let (lhs, rhs) = (self.0, other.0);
lhs.lt(&rhs)
}
fn le(&self, other: &Self) -> bool {
let (lhs, rhs) = (self.0, other.0);
lhs.le(&rhs)
}
fn gt(&self, other: &Self) -> bool {
let (lhs, rhs) = (self.0, other.0);
lhs.gt(&rhs)
}
fn ge(&self, other: &Self) -> bool {
let (lhs, rhs) = (self.0, other.0);
lhs.ge(&rhs)
}
}
impl<T: LmdbRawIfUnaligned + Ord> Ord for Unaligned<T> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
let (lhs, rhs) = (self.0, other.0);
lhs.cmp(&rhs)
}
}
impl<T: LmdbRawIfUnaligned + Hash> Hash for Unaligned<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
let v = self.0;
v.hash(state);
}
}
macro_rules! binop {
($tr:ident, $meth:ident) => {
impl<T: LmdbRawIfUnaligned + ops::$tr<T>> ops::$tr<Unaligned<T>> for Unaligned<T>
where
T::Output: LmdbRawIfUnaligned,
{
type Output = Unaligned<T::Output>;
fn $meth(self, rhs: Self) -> Self::Output {
let (lhs, rhs) = (self.0, rhs.0);
Unaligned(lhs.$meth(rhs))
}
}
};
}
macro_rules! binopeq {
($tr:ident, $meth:ident) => {
impl<T: LmdbRawIfUnaligned + ops::$tr<T>> ops::$tr<Unaligned<T>> for Unaligned<T> {
fn $meth(&mut self, rhs: Self) {
let (mut lhs, rhs) = (self.0, rhs.0);
lhs.$meth(rhs);
self.0 = lhs;
}
}
};
}
binop!(Add, add);
binop!(BitAnd, bitand);
binop!(BitOr, bitor);
binop!(BitXor, bitxor);
binop!(Div, div);
binop!(Mul, mul);
binop!(Rem, rem);
binop!(Shl, shl);
binop!(Shr, shr);
binop!(Sub, sub);
binopeq!(AddAssign, add_assign);
binopeq!(BitAndAssign, bitand_assign);
binopeq!(BitOrAssign, bitor_assign);
binopeq!(BitXorAssign, bitxor_assign);
binopeq!(DivAssign, div_assign);
binopeq!(MulAssign, mul_assign);
binopeq!(RemAssign, rem_assign);
binopeq!(ShlAssign, shl_assign);
binopeq!(ShrAssign, shr_assign);
binopeq!(SubAssign, sub_assign);