#![deny(missing_docs)]
#![deny(warnings)]
#![doc = include_str!("../README.md")]
#![cfg_attr(feature = "nightly", feature(proc_macro_hygiene, decl_macro))]
pub mod objects;
mod macros;
pub use oors_macros::*;
pub use objects::*;
#[allow(unused_imports)]
pub use macros::*;
#[cfg(test)]
mod tests {
use oors_macros::object;
use crate as oors; use crate::*;
#[allow(unused)]
mod multi_mod {
use super::*;
mod mod1 {
use super::*;
#[object]
pub struct FromMod1;
}
mod mod2 {
#[obj_use]
use crate::tests::multi_mod::mod1::FromMod1;
use super::*;
#[object(parent = FromMod1)]
pub struct FromMod2;
}
mod mod3 {
#[obj_use]
use crate::tests::multi_mod::mod2::FromMod2;
use super::*;
#[cfg(not(feature = "nightly"))]
use crate::tests::multi_mod::mod1::FromMod1;
#[object(parent = FromMod2)]
pub struct FromMod3;
}
}
#[object]
#[derive(Debug, Clone)]
pub struct ClassA {
pub val1: String,
pub val2: u64,
}
#[object(parent = ClassA)]
#[derive(Debug, Clone)]
pub struct ClassB {
val3: u16,
}
#[object(parent = ClassB)]
#[derive(Debug)]
pub struct ClassC {
pub val4: u64,
}
#[object(parent = ClassB)]
pub struct ClassC2 {
pub val4: String
}
#[object(parent = ClassB)]
pub struct ClassC3;
#[object(parent = ClassC3)]
pub struct ClassD(u32);
#[object_impl]
impl ClassD {
#[allow(unused)]
fn new() -> Typed<Self> {
let typed = Typed::new(
Self(
ClassC3(
ClassB::builder()
.with_val1("val".into())
.with_val2(0)
.with_val3(665)
.build_as_value()
),
5
)
);
assert_eq!(typed.val3(), &665); assert_eq!(typed.0.0.val3(), &665);
typed
}
}
#[object_impl(pub(self))]
impl ClassC {
fn new() -> Typed<ClassC> {
ClassC::builder()
.with_val1("val1".to_string())
.with_val2(2)
.with_val3(3)
.with_val4(4)
.build()
}
fn print_val4(&self) {
println!("{}", self.val4());
}
}
struct T;
__oors_recursive_impl_ClassD!(T);
const fn impl_t<T0: IsA<T1> + IsA<T2> + IsA<T3> + IsA<T4>, T1, T2, T3, T4>() {}
const _: fn() = || {
impl_t::<T, ClassA, ClassB, ClassC3, ClassD>();
};
#[test]
fn test_memery_leaks_and_insert() {
use std::alloc::System;
use stats_alloc::{Region, StatsAlloc, INSTRUMENTED_SYSTEM};
#[global_allocator]
static GLOBAL: &StatsAlloc<System> = &INSTRUMENTED_SYSTEM;
let region = Region::new(&GLOBAL);
for _ in 0..100 {
let class_c = ClassC::builder()
.with_val1("ClassA's val1".into())
.with_val2(2)
.insert_typed(ClassC::new()) .insert_typed(ClassC::new()) .with_val4(7)
.build();
assert_eq!(class_c.val1(), "val1"); assert_eq!(class_c.val2(), &2); assert_eq!(class_c.val3(), &3); assert_eq!(class_c.val4(), &7);
}
let after = region.change();
println!("{:?}", after);
assert!(after.allocations <= after.deallocations);
}
#[test]
fn test_cast() {
let mut class_c = ClassC::new(); let class_b = class_c.try_cast_mut::<ClassB>().unwrap();
let class_a = class_b.upcast_mut::<ClassA>();
class_a.try_cast_ref::<ClassC2>().expect_err("ClassC is not a ClassC2");
let class_a_bis = class_b.try_cast_ref::<ClassA>().expect("This is a ClassC");
let _unit = class_a_bis.try_cast_ref::<()>().expect("Everything is an unit");
assert_eq!(class_a_bis.val1(), "val1");
}
#[test]
fn test_builder() {
let class_c = ClassC::builder()
.with_val1("String".into())
.with_val2(2)
.with_val3(3)
.with_val4(4)
.build();
println!("{:#?}", &class_c);
assert_eq!(class_c.val1(), "String");
assert_eq!(*class_c.val2(), 2);
assert_eq!(*class_c.val3(), 3);
assert_eq!(*class_c.val4(), 4);
let _class_c_uninit = ClassB::builder()
.with_val2(2)
.with_val3(3)
.try_build()
.expect_err("Should not be considered totally initialized");
let class_c2_builder = ClassC2::builder()
.insert_typed(
ClassA::builder()
.with_val1("val1".into())
.with_val2(2)
.build()
);
assert!(!class_c2_builder.is_init(), "We did not initialize val3 and val4");
_ = class_c2_builder
.with_val3(3)
.with_val4("v".into())
.build();
}
}