tylisp 0.1.0

A domain-specific language for expressing complex type bounds
Documentation
#![recursion_limit = "512"]
#![cfg_attr(feature = "const",
            feature(const_generics,
                    const_panic,
                    const_evaluatable_checked,
))]
#![cfg_attr(feature = "const", allow(incomplete_features))]
//! # TyLisp: a domain-specific language for type-system calculations
//!
//! > This crate is still **experimental** and likely to undergo significant
//! > changes.
//! > It is developed primarily to support the needs of `memquery`.
//!
//! `tylisp` is a programming language embedded in Rust's macro and
//! type systems.
//! Its main purpose is to ease the burden of writing extremely-generic
//! Rust code that comes from a proliferation of trait bounds.
//! Because `tylisp` calculations occur entirely within the type system,
//! any object that the used operations support will automatically be
//! accepted.
//!
//! `tylisp` has two distinct operating modes:
//! * `Eval` mode will calculate a type, but doesn't provide any means to
//!   produce a value of that type.  It's mostly used to convey extra
//!   context informtion that can help select one of several implementations.
//! * `Calc` additionally provides a mechanism to apply the same actions to
//!   runtime values, which will produce a result value of the specified type.
//!   This allows us to define overloaded functions that have a return type
//!   dependent on argument types.
//! 
//! ## Semver Hazards
//! Writing code this way poses unique challenges to versioning.
//! All of the Rust functions defined via `tylisp` expose their internal
//! algorithm in the public API.
//! Thus, any change to the internal workings of a function have the
//! potential to break downstream code.
//! 
//! Best practice is to specify traditional trait bounds that constrain
//! the input and output types, and manually verify that the `tylisp`
//! code always satisfies these constraints.

#[cfg(not(feature = "const"))] pub use ::typenum_uuid::uuid_new_v4;
#[cfg(feature = "const")] pub use ::typenum_uuid::uuid_new_v4_literal;
#[cfg(feature = "const")] #[macro_export] macro_rules! uuid_new_v4 {
    ($($x:tt)*) => {
        $crate::ConstId<{$crate::uuid_new_v4_literal!()}>
    }
}

pub struct ConstId<const ID:u128>;

use typenum as tn; // 1.12.0;
pub use typenum;
#[cfg(frunk)] pub use frunk::{HNil,HCons};
#[cfg(not(frunk))]
#[derive(Debug,Default,Copy,Clone,Eq,PartialEq,Ord,PartialOrd,Hash)]
pub struct HNil;

#[cfg(not(frunk))]
#[derive(Debug,Default,Copy,Clone,Eq,PartialEq,Ord,PartialOrd,Hash)]
pub struct HCons<H,T> { pub head: H, pub tail: T }

#[macro_use]
pub mod macros;
pub mod engine;
pub mod ops;
pub mod marker_traits;

#[derive(Debug)]
pub struct Quote<T>(T);

// Required for any argument to Is
#[cfg(feature = "const")]
pub trait LispId:WithConstId { type Id; }
#[cfg(not(feature = "const"))]
pub trait LispId { type Id; }

pub trait WithConstId { const ID: u128; }

impl<T:LispId<Id=ConstId<ID>>, const ID:u128> WithConstId for T {
    const ID:u128 = ID;
}

#[cfg(feature="const")]
impl<T:LispId<Id=ConstId<ID>> + ?Sized, const ID:u128> LispId for std::marker::PhantomData<T> {
    type Id = T::Id;
}

#[cfg(not(feature="const"))]
impl<T:LispId + ?Sized> LispId for std::marker::PhantomData<T> {
    type Id = T::Id;
}

literal!{
              HNil;
          tn::True;
          tn::False;
          tn::Z0;
          tn::UTerm;
    {H,L} tn::UInt<H,L>
}