#![allow(clippy::ptr_offset_with_cast)]
#[macro_use]
mod impl_fieldoffset_methods;
mod repr_offset_ext_impls;
use crate::{
alignment::{Aligned, Alignment, CombineAlignment, CombineAlignmentOut, Unaligned},
offset_calc::GetNextFieldOffset,
utils::Mem,
};
use crate::get_field_offset::FieldOffsetWithVis;
use core::{
fmt::{self, Debug},
marker::PhantomData,
ops::Add,
};
#[cfg_attr(feature = "derive", doc = "use repr_offset::ReprOffset;")]
#[cfg_attr(not(feature = "derive"), doc = "use repr_offset_derive::ReprOffset;")]
#[repr(transparent)]
pub struct FieldOffset<S, F, A> {
offset: usize,
#[doc(hidden)]
pub tys: FOGhosts<S, F, A>,
}
#[doc(hidden)]
pub struct FOGhosts<S, F, A> {
pub struct_: PhantomData<fn() -> S>,
pub field: PhantomData<fn() -> F>,
pub alignment: PhantomData<fn() -> A>,
}
impl<S, F, A> Copy for FOGhosts<S, F, A> {}
impl<S, F, A> Clone for FOGhosts<S, F, A> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<S, F, A> FOGhosts<S, F, A> {
const NEW: Self = Self {
struct_: PhantomData,
field: PhantomData,
alignment: PhantomData,
};
}
#[doc(hidden)]
#[repr(transparent)]
pub struct FOAssertStruct<S, F, A> {
pub offset: FieldOffset<S, F, A>,
pub struct_: PhantomData<fn() -> S>,
}
impl_cmp_traits_for_offset! {
impl[S, F, A] FieldOffset<S, F, A>
}
impl<S, F, A> Debug for FieldOffset<S, F, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FieldOffset")
.field("offset", &self.offset)
.finish()
}
}
impl<S, F, A> Copy for FieldOffset<S, F, A> {}
impl<S, F, A> Clone for FieldOffset<S, F, A> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<S, F, A> FieldOffset<S, F, A> {
#[inline(always)]
pub const unsafe fn new(offset: usize) -> Self {
Self {
offset,
tys: FOGhosts::NEW,
}
}
#[inline(always)]
const fn priv_new(offset: usize) -> Self {
Self {
offset,
tys: FOGhosts::NEW,
}
}
pub const unsafe fn next_field_offset<Next, NextA>(self) -> FieldOffset<S, Next, NextA> {
let offset = GetNextFieldOffset {
previous_offset: self.offset,
previous_size: Mem::<F>::SIZE,
container_alignment: Mem::<S>::ALIGN,
next_alignment: Mem::<Next>::ALIGN,
}
.call();
FieldOffset {
offset,
tys: FOGhosts::NEW,
}
}
}
impl FieldOffset<(), (), Aligned> {
pub const fn identity<T>() -> FieldOffset<T, T, Aligned> {
FieldOffset {
offset: 0,
tys: FOGhosts::NEW,
}
}
}
impl<S, F> FieldOffset<S, F, Aligned> {
#[inline(always)]
pub const fn add<F2, A2>(self, other: FieldOffset<F, F2, A2>) -> FieldOffset<S, F2, A2> {
FieldOffset::priv_new(self.offset + other.offset)
}
}
impl<S, F> FieldOffset<S, F, Unaligned> {
#[inline(always)]
pub const fn add<F2, A2>(self, other: FieldOffset<F, F2, A2>) -> FieldOffset<S, F2, Unaligned> {
FieldOffset::priv_new(self.offset + other.offset)
}
}
impl<S, F, A, F2, A2> Add<FieldOffset<F, F2, A2>> for FieldOffset<S, F, A>
where
A: CombineAlignment<A2>,
A2: Alignment,
{
type Output = FieldOffset<S, F2, CombineAlignmentOut<A, A2>>;
#[inline(always)]
fn add(self, other: FieldOffset<F, F2, A2>) -> Self::Output {
FieldOffset::priv_new(self.offset + other.offset)
}
}
impl<S, F, A> FieldOffset<S, F, A> {
#[inline(always)]
pub const fn offset(self) -> usize {
self.offset
}
}
impl<S, F, A> FieldOffset<S, F, A> {
#[inline(always)]
pub const unsafe fn with_vis<V, FN>(self) -> FieldOffsetWithVis<S, V, FN, F, A> {
FieldOffsetWithVis::from_fieldoffset(self)
}
}
impl<S, F, A> FieldOffset<S, F, A> {
#[inline(always)]
pub const unsafe fn cast_struct<S2>(self) -> FieldOffset<S2, F, A> {
FieldOffset::new(self.offset)
}
#[inline(always)]
pub const unsafe fn cast_field<F2>(self) -> FieldOffset<S, F2, A> {
FieldOffset::new(self.offset)
}
#[inline(always)]
pub const fn to_unaligned(self) -> FieldOffset<S, F, Unaligned> {
FieldOffset {
offset: self.offset,
tys: FOGhosts::NEW,
}
}
#[inline(always)]
pub const unsafe fn to_aligned(self) -> FieldOffset<S, F, Aligned> {
FieldOffset::new(self.offset)
}
}
impl<S, F> FieldOffset<S, F, Aligned> {
#[inline(always)]
pub fn get(self, base: &S) -> &F {
unsafe { impl_fo!(fn get<S, F, Aligned>(self, base)) }
}
#[inline(always)]
pub fn get_mut(self, base: &mut S) -> &mut F {
unsafe { impl_fo!(fn get_mut<S, F, Aligned>(self, base)) }
}
#[inline(always)]
pub fn get_copy(self, base: &S) -> F
where
F: Copy,
{
unsafe { impl_fo!(fn get_copy<S, F, Aligned>(self, base)) }
}
}
impl<S, F, A> FieldOffset<S, F, A> {
#[inline(always)]
pub fn get_ptr(self, base: &S) -> *const F {
unsafe { impl_fo!(fn get_ptr<S, F, A>(self, base)) }
}
#[inline(always)]
pub fn get_mut_ptr(self, base: &mut S) -> *mut F {
unsafe { impl_fo!(fn get_mut_ptr<S, F, A>(self, base)) }
}
#[inline(always)]
pub unsafe fn raw_get(self, base: *const S) -> *const F {
impl_fo!(fn raw_get<S, F, A>(self, base))
}
#[inline(always)]
pub unsafe fn raw_get_mut(self, base: *mut S) -> *mut F {
impl_fo!(fn raw_get_mut<S, F, A>(self, base))
}
#[inline(always)]
pub fn wrapping_raw_get(self, base: *const S) -> *const F {
(base as *const u8).wrapping_offset(self.offset as isize) as *const F
}
#[inline(always)]
pub fn wrapping_raw_get_mut(self, base: *mut S) -> *mut F {
(base as *mut u8).wrapping_offset(self.offset as isize) as *mut F
}
}
impl<S, F> FieldOffset<S, F, Aligned> {
#[inline(always)]
pub unsafe fn read_copy(self, base: *const S) -> F
where
F: Copy,
{
impl_fo!(fn read_copy<S, F, Aligned>(self, base))
}
#[inline(always)]
pub unsafe fn read(self, source: *const S) -> F {
impl_fo!(fn read<S, F, Aligned>(self, source))
}
#[inline(always)]
pub unsafe fn write(self, destination: *mut S, value: F) {
impl_fo!(fn write<S, F, Aligned>(self, destination, value))
}
#[inline(always)]
pub unsafe fn copy(self, source: *const S, destination: *mut S) {
impl_fo!(fn copy<S, F, Aligned>(self, source, destination))
}
#[inline(always)]
pub unsafe fn copy_nonoverlapping(self, source: *const S, destination: *mut S) {
impl_fo!(fn copy_nonoverlapping<S, F, Aligned>(self, source, destination))
}
#[inline(always)]
pub unsafe fn replace(self, destination: *mut S, value: F) -> F {
impl_fo!(fn replace<S, F, Aligned>(self, destination, value))
}
#[inline(always)]
pub fn replace_mut(self, destination: &mut S, value: F) -> F {
unsafe { impl_fo!(fn replace_mut<S, F, Aligned>(self, destination, value)) }
}
#[inline(always)]
pub unsafe fn swap(self, left: *mut S, right: *mut S) {
impl_fo!(fn swap<S, F, Aligned>(self, left, right))
}
#[inline(always)]
pub unsafe fn swap_nonoverlapping(self, left: *mut S, right: *mut S) {
impl_fo!(fn swap_nonoverlapping<S, F, Aligned>(self, left, right))
}
#[inline(always)]
pub fn swap_mut(self, left: &mut S, right: &mut S) {
unsafe { impl_fo!(fn swap_mut<S, F, Aligned>(self, left, right)) }
}
}
impl<S, F> FieldOffset<S, F, Unaligned> {
#[inline(always)]
pub fn get_copy(self, base: &S) -> F
where
F: Copy,
{
unsafe { impl_fo!(fn get_copy<S, F, Unaligned>(self, base)) }
}
#[inline(always)]
pub unsafe fn read_copy(self, base: *const S) -> F
where
F: Copy,
{
impl_fo!(fn read_copy<S, F, Unaligned>(self, base))
}
#[inline(always)]
pub unsafe fn read(self, source: *const S) -> F {
impl_fo!(fn read<S, F, Unaligned>(self, source))
}
#[inline(always)]
pub unsafe fn write(self, source: *mut S, value: F) {
impl_fo!(fn write<S, F, Unaligned>(self, source, value))
}
#[inline(always)]
pub unsafe fn copy(self, source: *const S, destination: *mut S) {
impl_fo!(fn copy<S, F, Unaligned>(self, source, destination))
}
#[inline(always)]
pub unsafe fn copy_nonoverlapping(self, source: *const S, destination: *mut S) {
impl_fo!(fn copy_nonoverlapping<S, F, Unaligned>(self, source, destination))
}
}
impl<S, F> FieldOffset<S, F, Unaligned> {
#[inline(always)]
pub unsafe fn replace(self, dest: *mut S, value: F) -> F {
impl_fo!(fn replace<S, F, Unaligned>(self, dest, value))
}
pub fn replace_mut(self, dest: &mut S, value: F) -> F {
unsafe { impl_fo!(fn replace_mut<S, F, Unaligned>(self, dest, value)) }
}
}
impl<S, F> FieldOffset<S, F, Unaligned> {
#[inline(always)]
pub unsafe fn swap(self, left: *mut S, right: *mut S) {
impl_fo!(fn swap<S, F, Unaligned>(self, left, right))
}
#[inline(always)]
pub unsafe fn swap_nonoverlapping(self, left: *mut S, right: *mut S) {
impl_fo!(fn swap_nonoverlapping<S, F, Unaligned>(self, left, right))
}
#[inline(always)]
pub fn swap_mut(self, left: &mut S, right: &mut S) {
unsafe { impl_fo!(fn swap_mut<S, F, Unaligned>(self, left, right)) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types_for_tests::StructPacked;
use core::mem;
#[test]
fn test_constructor_offset() {
unsafe {
let field_0 = FieldOffset::<(u128,), u8, Aligned>::new(0);
let field_1 = field_0.next_field_offset::<u32, Aligned>();
assert_eq!(field_0.offset(), 0);
assert_eq!(field_1.offset(), mem::align_of::<u32>());
}
unsafe {
let field_0 = FieldOffset::<StructPacked<u128, (), (), ()>, u8, Unaligned>::new(0);
let field_1 = field_0.next_field_offset::<u32, Unaligned>();
let field_2 = field_1.next_field_offset::<&'static str, Unaligned>();
assert_eq!(field_0.offset(), 0);
assert_eq!(field_1.offset(), 1);
assert_eq!(field_2.offset(), 5);
}
}
}