#![doc = crate::doc_macro::make_svgbobdoc!(
//! Tuples of variable length types, potentially mixed with fixed-length types.
//!
//! Tuples of lengths 2-5 are supported. You may nest tuples arbitrarily.
//!
//! # Examples
//!
//! A fixed-length type (u32), with two variable-length types:
//!
//! ```
//! use varlen::prelude::*;
//! type Person = Tup3<FixedLen<u8> /* age */, Str /* name */, Str /* postal address */>;
//! let person: VBox<Person> = VBox::new(tup3::Init(
//! FixedLen(16),
//! Str::copy("Harry Potter"),
//! Str::copy("Cupboard under the stairs"),
//! ));
//! assert_eq!(16, person.refs().0.0);
//! assert_eq!("Harry Potter", &person.refs().1[..]);
)]
use crate::marker::FieldMarker;
use crate::newtype::impl_initializer_as_newtype;
use crate::{Initializer, VClone, VCopy, VarLen};
use core::concat;
use core::pin::Pin;
macro_rules! define_tuple {
(
$(#[$attr:meta])*
$name:ident< $($arg:ident),* >,
$mod:ident,
<$($fieldname:ident),*>,
<$($offset:ident),*>,
<$($layout:ident),*>,
<$($init:ident),*>
) => {
#[doc = concat!("Helper types for [`", stringify!($name), "`].")]
#[allow(rustdoc::missing_doc_code_examples)]
pub mod $mod {
use super::*;
$(#[$attr])*
pub struct Init<$($arg),*>($(pub $arg),*);
$(#[$attr])*
pub struct Refs<'a, $($arg),*>($(pub &'a $arg),*);
$(#[$attr])*
pub struct Muts<'a, $($arg),*>($(pub Pin<&'a mut $arg>),*);
pub struct Cloner<'a, $($arg: VClone<'a>),*>(pub(super) Init<$(<$arg as VClone<'a>>::Cloner),*>);
impl_initializer_as_newtype! {
impl<('a), $( ( $arg: VClone<'a> ) ),*> Initializer<$name<$($arg),*>>
for Cloner<'a, $($arg),*> { _ }
}
$(#[$attr])*
pub struct Layout<$($arg: VarLen),*>{
pub(super) size: usize,
$(
pub(super) $offset: usize,
pub(super) $layout: $arg::Layout
),*
}
impl<$($arg: VarLen),*> crate::Layout for Layout<$($arg),*> {
fn size(&self) -> usize {
self.size
}
}
}
$(#[$attr])*
pub struct $name<$($arg),*>($( pub FieldMarker<$arg> ),* );
#[allow(rustdoc::missing_doc_code_examples)]
impl<$($arg: VarLen),*> $name<$($arg),*> {
$(#[$attr])*
pub fn refs(&self) -> $mod::Refs<$($arg),*> {
let layout = self.calculate_layout();
$mod::Refs($(
unsafe { crate::macro_support::ref_field(self, layout.$offset) }
),*)
}
$(#[$attr])*
pub fn muts(self: Pin<&mut Self>) -> $mod::Muts<$($arg),*> {
let layout = self.calculate_layout();
unsafe {
let mut_ptr = self.get_unchecked_mut() as *mut _;
$mod::Muts(
$(
crate::macro_support::mut_field(mut_ptr, layout.$offset)
),*
)
}
}
}
unsafe impl<$($arg: VarLen),*> VarLen for $name<$($arg),*> {
type Layout = $mod::Layout<$($arg),*>;
const ALIGN: usize = crate::macro_support::array_max(&[
$($arg::ALIGN),*
]);
const NEEDS_VDROP: bool = $(
$arg::NEEDS_VDROP ||
)* false;
fn calculate_layout(&self) -> $mod::Layout<$($arg),*> {
let offset = core::mem::size_of::<Self>();
$(
let ($offset, $layout, offset) = crate::macro_support::cat_field_fast::<$arg, _>(self, offset);
)*
let size = offset;
$mod::Layout{size,
$( $offset, $layout ),*
}
}
unsafe fn vdrop(self: Pin<&mut Self>, layout: $mod::Layout<$($arg),*>) {
if !Self::NEEDS_VDROP {
return;
}
let p = self.get_unchecked_mut() as *mut _ as *mut u8;
$(
crate::macro_support::vdrop_field::<$arg>(p, layout.$offset, layout.$layout);
)*
}
}
unsafe impl<$($arg: VarLen, $init: Initializer<$arg>),*> Initializer<$name<$($arg),*>> for $mod::Init<$($init),*> {
fn calculate_layout_cautious(
&self,
) -> Option<$mod::Layout<$($arg),*>> {
let $mod::Init($($fieldname),*) = self;
let offset = core::mem::size_of::<$name<$($arg),*>>();
$(
let ($offset, $layout, offset) =
crate::macro_support::cat_field_cautious::<$arg, _>($fieldname, offset)?;
)*
let size = offset;
Some($mod::Layout {size,
$( $offset, $layout ),*
})
}
unsafe fn initialize(
self,
dst: core::ptr::NonNull<$name<$($arg),*>>,
layout: $mod::Layout<$($arg),*>,
) {
let $mod::Init($($fieldname),*) = self;
let header = $name(
$(
crate::macro_support::init_field(
$fieldname,
dst.cast::<u8>(),
layout.$offset,
layout.$layout,
)
),*
);
core::ptr::write(dst.as_ptr(), header);
}
}
impl<'a, $($arg: VClone<'a>),*> VClone<'a> for $name<$($arg),*> {
type Cloner = $mod::Cloner<'a, $($arg),*>;
fn vclone(&'a self) -> Self::Cloner {
let $mod::Refs($($fieldname),*) = self.refs();
$mod::Cloner(
$mod::Init(
$($fieldname.vclone()),*
)
)
}
}
unsafe impl<'a, $($arg: VCopy<'a>),*> VCopy<'a> for $name<$($arg),*> { }
impl<$($arg),*> Drop for $name<$($arg),*> {
fn drop(&mut self) {
crate::macro_support::invalid_drop_call()
}
}
}
}
define_tuple!(
Tup2<A, B>, tup2, <t0, t1>, <a_offset, b_offset>, <a_layout, b_layout>, <AInit, BInit>);
define_tuple!(
Tup3<A, B, C>, tup3, <t0, t1, t2>, <a_offset, b_offset, c_offset>, <a_layout, b_layout, c_layout>, <AInit, BInit, CInit>);
define_tuple!(
Tup4<A, B, C, D>, tup4, <t0, t1, t2, t3>, <a_offset, b_offset, c_offset, d_offset>, <a_layout, b_layout, c_layout, d_layout>, <AInit, BInit, CInit, DInit>);
define_tuple!(
Tup5<A, B, C, D, E>, tup5, <t0, t1, t2, t3, t4>, <a_offset, b_offset, c_offset, d_offset, e_offset>, <a_layout, b_layout, c_layout, d_layout, e_layout>, <AInit, BInit, CInit, DInit, EInit>);