use crate::prelude_lib::*;
#[derive(Debug)]
pub struct TableHeader {
pub name: Name,
pub marker: TypeId,
pub columns: Vec<ColumnHeader>,
}
pub trait TableMarker: 'static + Default + Copy + Send + Sync + Register + fmt::Debug {
const NAME: Name;
type RawId: Raw;
fn header() -> TableHeader;
}
#[derive(Debug, Clone)]
pub struct ColumnHeader {
pub column_type: TypeId,
pub element_type: TypeId,
pub name: Name,
pub foreign_table: Option<Name>,
}
#[macro_export]
macro_rules! decl_table {
(
$(#[doc = $doc:literal])*
$(#[row::$row_meta:meta])*
$vis:vis struct $name:ident {
$(
$(#[$cmeta:meta])*
pub $cn:ident: $cty:ty,
)*
}
) => {
$crate::decl_table! {
$(#[doc = $doc])*
$(#[row::$row_meta])*
#[raw_index(u32)]
$vis struct $name {
$(
$(#[$cmeta])*
pub $cn: $cty,
)*
}
}
};
(
$(#[doc = $doc:literal])*
$(#[row::$row_meta:meta])*
#[raw_index($raw:ty)]
$vis:vis struct $name:ident {
$(
$(#[$cmeta:meta])*
pub $cn:ident: $cty:ty,
)*
}
) => {
#[allow(non_camel_case_types, dead_code, non_upper_case_globals, non_snake_case)]
$(#[doc = $doc])*
$vis mod $name {
mod in_v9 {
use $crate::prelude_macro::*;
use super::in_user::{Read, Write, Edit, Row, RowRef};
pub const NAME: &'static str = stringify!($name);
pub type Id = IdV9<Marker>;
pub type Range = IdRange<'static, Id>;
pub type Ids = IdList<Marker>;
pub type CheckedId<'a> = CheckedIdV9<'a, Marker>;
pub const FIRST: IdV9<Marker> = IdV9(0);
pub const INVALID: IdV9<Marker> = IdV9(<$raw as Raw>::LAST);
#[derive(Default, Copy, Clone)]
pub struct Marker;
impl fmt::Debug for Marker {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", NAME)
}
}
impl fmt::Display for Marker {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", NAME)
}
}
pub mod names {
$(pub const $cn: &'static str = concat!(stringify!($name), ".", stringify!($cn));)*
}
impl<'a> Read<'a> {
pub fn len(&self) -> usize {
self.__v9__iter.len()
}
pub fn ids(&self) -> &Ids {
self.__v9__iter
}
pub fn clone_row(&self, i: impl 'a + Check<M=Marker>) -> Row {
self.ref_row(i).to_owned()
}
pub fn ref_row(&self, i: impl 'a + Check<M=Marker>) -> RowRef {
let i = self.ids().check(i);
RowRef {
$($cn: &self.$cn[i],)*
}
}
pub fn iter_all(&self) -> UncheckedIdRange<Marker> {
IdRange::to(Id::from_usize(self.__v9__iter.outer_capacity()))
}
pub fn iter(&self) -> CheckedIter<Marker> {
self.__v9__iter.iter()
}
}
impl<'a> Edit<'a> {
pub fn clone_row(&self, i: impl 'a + Check<M=Marker>) -> Row {
self.ref_row(i).to_owned()
}
pub fn ref_row(&self, i: impl 'a + Check<M=Marker>) -> RowRef {
RowRef {
$($cn: &self.$cn[i],)*
}
}
pub fn borrow(&'a self, ids: &'a Ids) -> Read<'a> {
Read {
$($cn: self.$cn.borrow(),)*
__v9__iter: ids,
}
}
}
impl<'a> Write<'a> {
pub fn clone_row(&self, i: impl 'a + Check<M=Marker>) -> Row {
self.ref_row(i).to_owned()
}
pub fn ref_row(&self, i: impl 'a + Check<M=Marker>) -> RowRef {
RowRef {
$($cn: &self.$cn[i],)*
}
}
#[inline]
pub fn len(&self) -> usize {
self.__v9__iter.len()
}
#[inline]
pub fn ids(&self) -> &Ids {
self.__v9__iter
}
#[inline]
pub fn ids_mut(&mut self) -> &mut Ids {
self.__v9__iter
}
pub fn reserve(&mut self, n: usize) {
unsafe {
$(self.$cn.col.get_mut().data_mut().reserve(n);)*
}
}
pub fn push(&mut self, row: Row) -> Id {
unsafe {
match self.__v9__iter.recycle_id() {
Ok(id) => {
self.set_immediate(id.to_usize(), row);
id
},
Err(id) => {
self.push_immediate(row);
id
},
}
}
}
pub unsafe fn push_immediate(&mut self, row: Row) {
$(self.$cn.col.get_mut().data_mut().push(row.$cn);)*
}
pub unsafe fn set_immediate(&mut self, i: usize, row: Row) {
$(
*self.$cn.col.get_mut().data_mut().get_unchecked_mut(i) = row.$cn;
)*
}
pub fn push_contiguous(&mut self, rows: impl IntoIterator<Item=Row>) -> Range {
use $crate::util::die::bad_iter_len;
let rows = rows.into_iter();
let n = {
let (min, max) = rows.size_hint();
if Some(min) != max {
bad_iter_len();
}
min
};
unsafe {
match self.ids_mut().recycle_id_contiguous(n) {
Ok(range) => {
let mut id_iter = range.iter();
for row in rows {
let id = id_iter.next().expect($crate::util::die::BAD_ITER_LEN);
self.set_immediate(id.to_usize(), row);
}
if id_iter.next().is_some() {
bad_iter_len();
}
range
},
Err(range) => {
for row in rows {
self.push_immediate(row);
}
range
},
}
}
}
pub fn borrow(&self) -> Read {
Read {
$($cn: self.$cn.borrow(),)*
__v9__iter: self.__v9__iter, }
}
pub fn remove(&mut self, i: impl Into<Id>) {
self.__v9__iter.delete(i.into());
}
pub fn iter_all(&self) -> IdRange<Id> {
IdRange::to(Id::from_usize(self.__v9__iter.outer_capacity()))
}
pub fn iter(&self) -> CheckedIter<Marker> {
self.__v9__iter.iter()
}
pub fn clear(&mut self) {
let to_delete = self.iter().map(|i| i.uncheck()).collect::<Vec<_>>();
for id in to_delete {
self.remove(id);
}
}
}
}
#[allow(unused_imports)]
mod in_user {
use super::super::*;
use $crate::prelude_macro::ForeignKey as _;
impl $crate::prelude_macro::TableMarker for super::Marker {
const NAME: &'static str = super::in_v9::NAME;
type RawId = $raw;
fn header() -> $crate::prelude_macro::TableHeader {
$crate::prelude_macro::TableHeader {
name: Self::NAME,
marker: $crate::prelude_macro::TypeId::of::<super::Marker>(),
columns: vec![$($crate::prelude_macro::ColumnHeader {
column_type: $crate::prelude_macro::TypeId::of::<self::types::$cn>(),
element_type: $crate::prelude_macro::TypeId::of::<self::own::$cn>(),
name: super::names::$cn,
foreign_table: {
type T = $cty;
T::__v9_link_foreign_table_name()
},
}),*],
}
}
}
impl $crate::prelude_macro::Register for super::Marker {
fn register(universe: &mut $crate::prelude_macro::Universe) {
universe.add_mut(
$crate::prelude_macro::TypeId::of::<super::Marker>(),
<Self as $crate::prelude_macro::TableMarker>::header(),
);
universe.add_mut(
$crate::prelude_macro::TypeId::of::<$crate::prelude_macro::IdList<super::Marker>>(),
$crate::prelude_macro::IdList::<super::Marker>::default(),
);
$(universe.add_mut(
$crate::prelude_macro::TypeId::of::<$crate::prelude_macro::Column<super::Marker, $cty>>(),
$crate::prelude_macro::Column::<super::Marker, $cty>::new(),
);)*
$({
type T = $cty;
T::__v9_link_foreign_key::<super::Marker>(universe);
})*
}
}
#[derive(Debug, Clone)]
$(#[$row_meta])*
pub struct Row {
$(
$(#[$cmeta])*
pub $cn: $cty,
)*
}
#[derive(Debug, Clone)]
pub struct RowRef<'a> {
$(pub $cn: &'a $cty,)*
}
impl<'a> RowRef<'a> {
#[inline]
pub fn to_owned(&self) -> Row {
Row {
$($cn: self.$cn.clone(),)*
}
}
}
pub mod types {
#[allow(unused_imports)]
use super::super::super::*;
$(pub type $cn = $cty;)*
}
pub mod own {
$(pub type $cn = $crate::prelude_macro::Column<super::super::in_v9::Marker, super::types::$cn>;)*
}
pub mod read {
$(pub type $cn<'a> = $crate::prelude_macro::ReadColumn<'a, super::super::in_v9::Marker, super::types::$cn>;)*
pub type __V9__Iter<'a> = &'a $crate::prelude_macro::IdList<super::super::in_v9::Marker>;
$crate::decl_context! {
pub struct __Read {
$(pub $cn: $cn,)*
pub(in super::super::super) __v9__iter: __V9__Iter,
}
}
}
pub use self::read::__Read as Read;
pub mod edit {
$(pub type $cn<'a> = $crate::prelude_macro::EditColumn<'a, super::super::in_v9::Marker, super::types::$cn>;)*
#[doc(hidden)]
$crate::decl_context! {
pub struct __Edit {
$(pub $cn: $cn,)*
}
}
}
pub use self::edit::__Edit as Edit;
pub mod write {
$(pub type $cn<'a> = $crate::prelude_macro::WriteColumn<'a, super::super::in_v9::Marker, super::types::$cn>;)*
#[doc(hidden)]
pub type __V9__Iter<'a> = &'a mut super::super::in_v9::Ids;
$crate::decl_context! {
pub struct __Write {
$(pub $cn: $cn,)*
#[doc(hidden)]
pub(in super::super::super) __v9__iter: __V9__Iter,
}
}
}
pub use self::write::__Write as Write;
}
pub use self::in_v9::*;
pub use self::in_user::*;
}
};
}
#[cfg(test)]
mod test {
pub use super::*;
decl_table! {
pub struct bobs {
pub name: Name,
pub digestion_count: u64,
}
}
#[test]
fn register() {
let mut universe = Universe::new();
bobs::Marker::register(&mut universe);
}
#[test]
#[should_panic]
fn double_register() {
let mut universe = Universe::new();
bobs::Marker::register(&mut universe);
bobs::Marker::register(&mut universe);
}
#[test]
#[should_panic]
fn duplicate_column_types() {
decl_table! {
pub struct dupes {
pub speed: f32,
pub scale: f32,
}
}
dupes::Marker::register(&mut Universe::new());
}
#[test]
fn basics() {
let universe = &mut Universe::new();
bobs::Marker::register(universe);
universe.kmap(|mut bobs: bobs::Write| {
bobs.reserve(3);
bobs.push(bobs::Row {
name: "Bob",
digestion_count: 237,
});
bobs.push(bobs::Row {
name: "Bob",
digestion_count: 42,
});
bobs.push(bobs::Row {
name: "Bob",
digestion_count: 69,
});
});
universe.kmap(|bobs: bobs::Read| {
println!("{:?}", bobs.clone_row(bobs::FIRST));
});
}
#[test]
fn separate_col_access() {
let universe = &mut Universe::new();
bobs::Marker::register(universe);
universe.kmap(|_: bobs::read::name, _: bobs::edit::digestion_count| {});
}
}
#[cfg(not(release))]
pub mod example {
decl_table! {
pub struct cheeses {
pub quantity: f64,
pub stinky: bool,
}
}
}