mem-query 0.0.1

Relational algebra interface for Rust collections
//! Definition of fields for relational tuples.
//!
//! At the very core of the memquery engine is the `Col` trait,
//! and the `col!` macro that produces new column types that
//! implement the trait.
//!
//! Each `Col` is a transparent newtype that represents a
//! single data cell in a relational table.  It has very few
//! methods of its own and `Deref`s to its inner type, so you
//! can use a column cell in most places that expect the value
//! stored there.

use crate::prelude::*;

use crate::rename_col::RenameCol;

use core::ops::{Deref,DerefMut};
use core::borrow::{Borrow,BorrowMut};
use tylisp::LispId;

/// A trait to represent a relation field
///
/// It is intended to only be implemented via the `col!` macro,
/// which will define a new column type and implement all of
/// the required traits.
pub trait Col: 'static
             + Clone
             + From<<Self as Col>::Inner>
             + Into<<Self as Col>::Inner>
             + Deref<Target = <Self as Col>::Inner>
             + DerefMut
             + AsRef<<Self as Col>::Inner>
             + AsMut<<Self as Col>::Inner>
             + Borrow<<Self as Col>::Inner>
             + BorrowMut<<Self as Col>::Inner>
             + ColProxy< For=Self >
             + LispId
             + crate::record::Record<Cols=tylisp::sexpr!{Self}>
             + tylisp::engine::Eval<Result=Self>
{
    type Inner;

    /// Safely transmutes a shared reference to the
    /// inner datatype into a shared column reference
    fn wrap_ref(x: &Self::Inner)->&Self;

    /// Safely transmutes an exclusive reference to
    /// the inner datatype into an exclusive column reference
    fn wrap_mut(x: &mut Self::Inner)->&mut Self;

    fn inner_ref(&self)->&Self::Inner { self.deref() }

    /// Tags the inner variable with a different column wrapper
    fn rename<New: Col<Inner=Self::Inner>>(self)->New
    { New::from(<Self as Into<Self::Inner>>::into(self) ) }

    /// In-place renaming of a shared reference to this column
    /// as a different column name.
    fn rename_ref<New: Col<Inner=Self::Inner>>(&self)->&New
    { New::wrap_ref(self.deref()) }

    /// In-place renaming of an exclusive reference to this column
    /// as a different column name.
    fn rename_mut<New: Col<Inner=Self::Inner>>(&mut self)->&mut New
    { New::wrap_mut(self.deref_mut()) }
}

/// A value that stands in for a column
/// 
/// This trait should be implemented for smart pointers to columns,
/// in addition to the columns themselves.  This trait is often used
/// as a bound where you might ordinarily expect to see a column
/// reference so that the column value itself can be used in place
/// of the reference.
pub trait ColProxy {
    /// Which column does this proxy represent?
    type For: Col;

    /// Consume the proxy and produce an owned version of the
    /// column data.  This will often involve `clone()`ing the
    /// column value.
    fn into_col(self)->Self::For;

    /// Get a reference to the column value without consuming
    /// the pointer.
    fn col_ref(&self)->&Self::For;
}

/// A macro to define a field.
///
/// The `col!` macro defines a column type that will properly
/// interact with `memquery`.
/// The inner type must be `'static` and cannot take any generic
/// parameters.
///
/// Most derivable traits in `std` are automatically implemented
/// for the resulting type.
/// 
/// ```
/// # #![recursion_limit = "256"]
/// # #![cfg_attr(feature = "const", feature(const_generics, const_evaluatable_checked))]
/// # use ::mem_query::col;
/// col!{ pub TestField: u32 }
/// ```
#[macro_export]
macro_rules! col {
    ($viz:vis $name:ident : $ty:ty $(; $($derive:ident),*)?) => {
        #[repr(transparent)]
        #[derive(Debug, Copy, Clone, Hash, Default,
                 Ord, PartialOrd, Eq, PartialEq
                 $($(, $derive)*)?)]
        // Note: This is generic only to make the derive macros work.
        //       Using the resulting struct with any type other than
        //       the default is unlikely to be useful.
        $viz struct $name<T=$ty>(pub T);
        impl $crate::col::Col for $name {
            type Inner = $ty;

            fn wrap_ref(x: &Self::Inner)->&Self { x.into() }
            fn wrap_mut(x: &mut Self::Inner)->&mut Self { x.into() }
        }
        $crate::prelude::tylisp::non_calc_literal!{$name}
        impl ::core::convert::From<$ty> for $name {
            fn from(x:$ty)->Self { $name(x) }
        }
        impl ::core::convert::Into<$ty> for $name {
            fn into(self)->$ty { self.0 }
        }
        impl<T> ::core::borrow::Borrow<T> for $name
        where $ty: ::core::borrow::Borrow<T> {
            fn borrow(&self)->&T { <$ty as ::core::borrow::Borrow<T>>::borrow(&self.0) }
        }
        impl<T> ::core::borrow::BorrowMut<T> for $name
        where $ty: ::core::borrow::BorrowMut<T> {
            fn borrow_mut(&mut self)->&mut T { self.0.borrow_mut() }
        }
        impl ::core::ops::Deref for $name {
            type Target = $ty;
            fn deref(&self)->&$ty { &self.0 }
        }
        impl ::core::ops::DerefMut for $name {
            fn deref_mut(&mut self)->&mut $ty { &mut self.0 }
        }
        impl ::core::convert::AsRef<$ty> for $name {
            fn as_ref(&self)->&$ty { &self.0 }
        }
        impl ::core::convert::AsMut<$ty> for $name {
            fn as_mut(&mut self)->&mut $ty { &mut self.0 }
        }
        impl<AAAAA:$crate::col::Col, BBBBB:$crate::col::Col<Inner=AAAAA::Inner>, Renamed>
            $crate::rename_col::RenameCol<AAAAA,BBBBB> for $name
            where
            $crate::tylisp::sexpr!{$crate::tylisp::ops::If,
                {$crate::tylisp::ops::Is, @AAAAA, @$name},
                @BBBBB,
                @$name
            }: tylisp::engine::Eval<Result = Renamed>,
            Renamed: $crate::col::Col<Inner = $ty>
        {
            type Renamed = Renamed;
            fn rename_col(self)->Renamed { <Self as $crate::col::Col>::rename(self) }
        }
        impl<'a, AAAAA:$crate::col::Col, BBBBB:$crate::col::Col<Inner=AAAAA::Inner>, Renamed>
            $crate::rename_col::RenameCol<AAAAA,BBBBB> for &'a $name
            where
            $crate::tylisp::sexpr!{$crate::tylisp::ops::If,
                {$crate::tylisp::ops::Is, @AAAAA, @$name},
                @BBBBB,
                @$name
            }: tylisp::engine::Eval<Result = Renamed>,
            Renamed: $crate::col::Col<Inner = $ty>
        {
            type Renamed = &'a Renamed;
            fn rename_col(self)->&'a Renamed { <$name as $crate::col::Col>::rename_ref(self) }
        }
        impl<'a> ::core::convert::From<&'a $ty> for &'a $name {
            fn from(x: &'a $ty)->&'a $name {
                // Safety: Self is #[repr(transparent)] and columns
                // don't restrict their inner type, so transmuting
                // a reference should be sound
                unsafe { std::mem::transmute(x) }
            }
        }
        impl<'a> ::core::convert::From<&'a mut $ty> for &'a mut $name {
            fn from(x: &'a mut $ty)->&'a mut $name {
                // Safety: Self is #[repr(transparent)] and columns
                // don't restrict their inner type, so transmuting
                // a reference should be sound.
                //
                // No aliasing is introduced because the old reference
                // is destroyed in the transmute process.
                unsafe { std::mem::transmute(x) }
            }
        }


        impl $crate::col::ColProxy for $name {
            type For = Self;
            #[inline(always)]
            fn into_col(self)->Self::For { self }
            #[inline(always)]
            fn col_ref(&self)->&Self::For { self }
        }
        impl $crate::record::Record for $name {
            type Cols = $crate::tylisp::sexpr!{Self};
            
            #[inline(always)]
            fn into_cols(self)->Self::Cols {
                $crate::tylisp::sexpr_val!{self}
            }
            #[inline(always)]
            fn clone_cols(&self)->Self::Cols {
                $crate::tylisp::sexpr_val!{self.clone()}
            }
            #[inline(always)]
            fn col_ref<C:$crate::col::Col>(&self)->&C { //where Self::Cols: HasCol<C> {
                match self.col_opt() {
                    Some(x) => x,
                    None => { unreachable!() }
                }
            }
            #[inline(always)]
            fn col_opt<C:$crate::col::Col>(&self)->Option<&C> {
                (self as &dyn ::core::any::Any).downcast_ref()
            }
        }
        impl $crate::record::FromRecordImpl for $name {
            type Cols = $crate::tylisp::sexpr!{Self};

            fn from_rec_raw(rec: impl $crate::record::Record<Cols=Self::Cols>)->Self {
                rec.into_cols().head
            }
        }
        impl<'a> $crate::record::FromExternalRecord<'a> for $name {
            type Cols = $crate::tylisp::sexpr!{Self};

            fn from_ext_rec_raw(rec: impl $crate::record::ExternalRecord<'a,Cols=Self::Cols>)->Self {
                rec.into_cols().head
            }
        }
        impl<'a> $crate::record::FromExternalRecord<'a> for &'a $name {
            type Cols = $crate::tylisp::sexpr!{$name};

            fn from_ext_rec_raw(rec: impl $crate::record::ExternalRecord<'a,Cols=Self::Cols>)->Self {
                rec.ext_col_ref()
            }
        }
    }
}

macro_rules! proxy_impls {
    (< $param:tt > $( $ptr:ty ),* $(,)?) => {$(
        impl<$param:Col> ColProxy for $ptr {
            type For = $param;
            fn into_col(self)->Self::For { (*self).clone() }
            fn col_ref(&self)->&Self::For { self.deref() }
        }
    )*}
}

proxy_impls!{<C>
    &C,
    Box<C>,
}

proxy_impls!{<C>
    std::rc::Rc<C>,
    std::sync::Arc<C>,
}
    
/*
mod sealed {
    use crate::prelude::*;
    pub trait CmpColId<Other:Col>: Col {
        type IsSame;
    }

    impl<C1:Col, C2:Col> CmpColId<C1> for C2
    where C1::Id: typenum::IsEqual<C2::Id> {
        type IsSame = <C1::Id as typenum::IsEqual<C2::Id>>::Output;
    }
}

pub trait CmpColId<Other:Col>: sealed::CmpColId<Other> {
    type IsSame;
}

impl<A:Col,B:Col> CmpColId<B> for A where A: sealed::CmpColId<B> {
    type IsSame = <Self as sealed::CmpColId<B>>::IsSame;
}
*/
//pub trait Distinct<Other:Col>: Col
//    + sealed::CmpColId<Other, IsSame=typenum::False> {}

//impl<A:Col, B:Col> Distinct<B> for A
//where A: sealed::CmpColId<B, IsSame=typenum::False> {}



#[cfg(test)] mod test {
    use super::*;
    #[derive(Clone)]
    struct MyStruct;
    col!{ TestField2: MyStruct }

}