use core::cell::RefCell;
use core::ffi::CStr;
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
};
use core::panic::AssertUnwindSafe;
use core::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
AtomicU64, AtomicU8, AtomicUsize,
};
use alloc::boxed::Box;
use alloc::vec::Vec;
use alloc::ffi::CString;
use alloc::string::String;
#[cfg(feature = "std")]
use std::{
path::{Path, PathBuf},
ffi::{OsStr, OsString}
};
use crate::lists::{LinkedList, LinkedQueue};
#[cfg_attr(
feature = "derive",
doc = r"```rust"
)]
#[cfg_attr(
not(feature = "derive"),
doc = r"```rust,ignore"
)]
#[doc = r"# use rust_cc::*;
# use rust_cc_derive::*;
#[derive(Finalize)]
struct Foo {
// ...
}
```"]
pub trait Finalize {
#[inline(always)]
fn finalize(&self) {}
}
#[cfg_attr(
feature = "derive",
doc = r"```rust"
)]
#[cfg_attr(
not(feature = "derive"),
doc = r"```rust,ignore"
)]
#[doc = r"# use rust_cc::*;
# use rust_cc_derive::*;
# #[derive(Finalize)]
#[derive(Trace)]
struct Foo<A: Trace + 'static, B: Trace + 'static> {
a_field: Cc<A>,
another_field: Cc<B>,
}
```"]
pub unsafe trait Trace: Finalize {
fn trace(&self, ctx: &mut Context<'_>);
}
pub struct Context<'a> {
inner: ContextInner<'a>,
_phantom: PhantomData<*mut ()>, }
pub(crate) enum ContextInner<'a> {
Counting {
root_list: &'a mut LinkedList,
non_root_list: &'a mut LinkedList,
queue: &'a mut LinkedQueue,
},
RootTracing {
non_root_list: &'a mut LinkedList,
queue: &'a mut LinkedQueue,
},
}
impl<'b> Context<'b> {
#[inline]
#[must_use]
pub(crate) const fn new(ctxi: ContextInner) -> Context {
Context {
inner: ctxi,
_phantom: PhantomData,
}
}
#[inline]
pub(crate) fn inner<'a>(&'a mut self) -> &'a mut ContextInner<'b>
where
'b: 'a,
{
&mut self.inner
}
}
macro_rules! empty_trace {
($($this:ty),*,) => {
$(
unsafe impl $crate::trace::Trace for $this {
#[inline(always)]
fn trace(&self, _: &mut $crate::trace::Context<'_>) {}
}
impl $crate::trace::Finalize for $this {
}
)*
};
}
empty_trace! {
(),
bool,
isize,
usize,
i8,
u8,
i16,
u16,
i32,
u32,
i64,
u64,
i128,
u128,
f32,
f64,
char,
str,
CStr,
String,
CString,
NonZeroIsize,
NonZeroUsize,
NonZeroI8,
NonZeroU8,
NonZeroI16,
NonZeroU16,
NonZeroI32,
NonZeroU32,
NonZeroI64,
NonZeroU64,
NonZeroI128,
NonZeroU128,
AtomicBool,
AtomicIsize,
AtomicUsize,
AtomicI8,
AtomicU8,
AtomicI16,
AtomicU16,
AtomicI32,
AtomicU32,
AtomicI64,
AtomicU64,
}
#[cfg(feature = "std")]
empty_trace! {
Path,
OsStr,
PathBuf,
OsString,
}
unsafe impl<T: ?Sized> Trace for PhantomData<T> {
#[inline(always)]
fn trace(&self, _: &mut Context<'_>) {}
}
impl<T: ?Sized> Finalize for PhantomData<T> {}
macro_rules! deref_trace {
($generic:ident; $this:ty; $($bound:tt)*) => {
unsafe impl<$generic: $($bound)* $crate::trace::Trace> $crate::trace::Trace for $this
{
#[inline]
fn trace(&self, ctx: &mut $crate::trace::Context<'_>) {
let deref: &$generic = <$this as ::core::ops::Deref>::deref(self);
<$generic as $crate::trace::Trace>::trace(deref, ctx);
}
}
impl<$generic: $($bound)* $crate::trace::Finalize> $crate::trace::Finalize for $this
{
#[inline]
fn finalize(&self) {
let deref: &$generic = <$this as ::core::ops::Deref>::deref(self);
<$generic as $crate::trace::Finalize>::finalize(deref);
}
}
}
}
macro_rules! deref_traces {
($($this:tt),*,) => {
$(
deref_trace!{T; $this<T>; ?::core::marker::Sized +}
)*
}
}
macro_rules! deref_traces_sized {
($($this:tt),*,) => {
$(
deref_trace!{T; $this<T>; }
)*
}
}
deref_traces! {
Box,
ManuallyDrop,
}
deref_traces_sized! {
AssertUnwindSafe,
}
unsafe impl<T: ?Sized + Trace> Trace for RefCell<T> {
#[inline]
fn trace(&self, ctx: &mut Context<'_>) {
if let Ok(borrow) = self.try_borrow_mut() {
borrow.trace(ctx);
}
}
}
impl<T: ?Sized + Finalize> Finalize for RefCell<T> {
#[inline]
fn finalize(&self) {
if let Ok(borrow) = self.try_borrow() {
borrow.finalize();
}
}
}
unsafe impl<T: Trace> Trace for Option<T> {
#[inline]
fn trace(&self, ctx: &mut Context<'_>) {
if let Some(inner) = self {
inner.trace(ctx);
}
}
}
impl<T: Finalize> Finalize for Option<T> {
#[inline]
fn finalize(&self) {
if let Some(value) = self {
value.finalize();
}
}
}
unsafe impl<R: Trace, E: Trace> Trace for Result<R, E> {
#[inline]
fn trace(&self, ctx: &mut Context<'_>) {
match self {
Ok(ok) => ok.trace(ctx),
Err(err) => err.trace(ctx),
}
}
}
impl<R: Finalize, E: Finalize> Finalize for Result<R, E> {
#[inline]
fn finalize(&self) {
match self {
Ok(value) => value.finalize(),
Err(err) => err.finalize(),
}
}
}
unsafe impl<T: Trace, const N: usize> Trace for [T; N] {
#[inline]
fn trace(&self, ctx: &mut Context<'_>) {
for elem in self {
elem.trace(ctx);
}
}
}
impl<T: Finalize, const N: usize> Finalize for [T; N] {
#[inline]
fn finalize(&self) {
for elem in self {
elem.finalize();
}
}
}
unsafe impl<T: Trace> Trace for [T] {
#[inline]
fn trace(&self, ctx: &mut Context<'_>) {
for elem in self {
elem.trace(ctx);
}
}
}
impl<T: Finalize> Finalize for [T] {
#[inline]
fn finalize(&self) {
for elem in self {
elem.finalize();
}
}
}
unsafe impl<T: Trace> Trace for Vec<T> {
#[inline]
fn trace(&self, ctx: &mut Context<'_>) {
for elem in self {
elem.trace(ctx);
}
}
}
impl<T: Finalize> Finalize for Vec<T> {
#[inline]
fn finalize(&self) {
for elem in self {
elem.finalize();
}
}
}
macro_rules! tuple_finalize_trace {
($($args:ident),+) => {
#[allow(non_snake_case)]
unsafe impl<$($args),*> $crate::trace::Trace for ($($args,)*)
where $($args: $crate::trace::Trace),*
{
#[inline]
fn trace(&self, ctx: &mut $crate::trace::Context<'_>) {
match self {
($($args,)*) => {
$(
<$args as $crate::trace::Trace>::trace($args, ctx);
)*
}
}
}
}
#[allow(non_snake_case)]
impl<$($args),*> $crate::trace::Finalize for ($($args,)*)
where $($args: $crate::trace::Finalize),*
{
#[inline]
fn finalize(&self) {
match self {
($($args,)*) => {
$(
<$args as $crate::trace::Finalize>::finalize($args);
)*
}
}
}
}
}
}
macro_rules! tuple_finalize_traces {
($(($($args:ident),+);)*) => {
$(
tuple_finalize_trace!($($args),*);
)*
}
}
tuple_finalize_traces! {
(A);
(A, B);
(A, B, C);
(A, B, C, D);
(A, B, C, D, E);
(A, B, C, D, E, F);
(A, B, C, D, E, F, G);
(A, B, C, D, E, F, G, H);
(A, B, C, D, E, F, G, H, I);
(A, B, C, D, E, F, G, H, I, J);
(A, B, C, D, E, F, G, H, I, J, K);
(A, B, C, D, E, F, G, H, I, J, K, L);
}