//! Trait for getting the `FieldOffset` of a field, and related items.
//!
//! One would implement the [`ImplsGetFieldOffset`] and [`GetFieldOffset`] traits,
//! and use [`GetPubFieldOffset`] as a bound.
//!
//! [`ImplsGetFieldOffset`]: ./trait.ImplsGetFieldOffset.html
//! [`GetFieldOffset`]: ./trait.GetFieldOffset.html
//! [`GetPubFieldOffset`]: ./trait.GetPubFieldOffset.html
use crate::;
use PhantomData;
//////////////////////////////////////////////////////////////////////////////////
/// Marker trait for types that implement `GetFieldOffset`.
///
/// This trait is required for the `GetFieldOffset` impls that
/// get the [`FieldOffset`] of nested fields.
///
///
/// [`FieldOffset`]: ../struct.FieldOffset.html
///
/// This is only required as a workaround to lower the time that `cargo doc` takes to run.
pub unsafe
//////////////////////////////////////////////////////////////////////////////////
/// Hack use by `repr_offset` to implement `GetFieldOffset<(N0, N1, ...)>`
/// for all types without blowing up the time that `cargo doc` takes to run.
;
//////////////////////////////////////////////////////////////////////////////////
/// For getting the offset of a field given its name.
///
/// This trait exists to make it possible for the
/// [`OFF!`], [`off`], [`PUB_OFF!`], and [`pub_off`] macros
/// to get the [`FieldOffset`] of a field.
///
/// This trait is by default implemented by the [`unsafe_struct_field_offsets`] macro,
/// and [`ReprOffset`] derive macro.
///
/// [`unsafe_struct_field_offsets`]: ../macro.unsafe_struct_field_offsets.html
/// [`ReprOffset`]: ../derive.ReprOffset.html
///
/// # Safety
///
/// ### Non-nested fields
///
/// Implementors must ensure that for any given impl of `GetFieldOffset<TS!(<field_name>)>`
/// for a type there is a `<field_name>` field stored inline in the type,
/// accessible through `.<field_name>`.
///
/// Implementors must ensure that the
/// [`OFFSET_WITH_VIS`](#associatedconstant.OFFSET_WITH_VIS)
/// associated constant contains the [`FieldOffset`] for the `<field_name>` field,
/// with the correct offset(in bytes), field type, and alignment type parameter.
///
/// Implementors must ensure that there is the only one impl of
/// `GetFieldOffset` for that type through
/// which one can get the [`FieldOffset`] for the `<field_name>` field,
///
/// `<field_name>` is used here to refer to any one field (eg: a field named `foo`),
/// all mentions of that field in this section refer to the same field.
///
///
/// # SemVer
///
/// Impls of this trait where the `Privacy` associated type is `Private`
/// can change or be removed in semver compatible versions,
///
/// Prefer using the [`GetPubFieldOffset`] trait alias for bounds instead,
/// since that is for public fields.
///
/// # Type Parameter
///
/// The `FN` type parameter is the path to the field that this gets the offset for, it can be:
///
/// - A [`tstr::TStr`]: representing a single field, eg: (`tstr::TS!(foo)`).
///
/// - A tuple of [`tstr::TStr`]s: representing a nested field, eg: (`tstr::TS!(foo,bar,baz)`).
///
/// # Example
///
/// ### Manual Implementation
///
/// This example demonstrates how you can implement `GetFieldOffset` manually.
///
/// ```rust
/// use repr_offset::{
/// alignment::{Aligned, Unaligned},
/// get_field_offset::{GetFieldOffset, FieldOffsetWithVis as FOWithVis},
/// privacy::{IsPublic, IsPrivate},
/// tstr::TS,
/// off, pub_off,
/// FieldOffset, ROExtAcc, ROExtOps,
/// };
///
/// #[repr(C, packed)]
/// struct Foo {
/// wheel_count: u8,
/// pub(crate) seat_size: u128,
/// pub is_automatic: bool,
/// }
///
/// let foo = Foo {
/// wheel_count: 3,
/// seat_size: 5,
/// is_automatic: false,
/// };
///
/// // We can get a reference because the field is aligned.
/// assert_eq!(foo.f_get(off!(wheel_count)), &3);
///
/// // The seat_size field is unaligned inside of Foo, so we can't get a reference.
/// assert_eq!(foo.f_get_copy(off!(seat_size)), 5);
///
/// // We can get a reference because the field is aligned.
/// //
/// // Also, because the field is public, you can use `pub_off` to get its FieldOffset.
/// assert_eq!(foo.f_get(pub_off!(is_automatic)), &false);
///
///
/// unsafe impl GetFieldOffset<TS!(wheel_count)> for Foo {
/// type Type = u8;
/// type Alignment = Aligned;
/// type Privacy = IsPrivate;
///
/// const OFFSET_WITH_VIS: FOWithVis<Self, IsPrivate, TS!(wheel_count), u8, Aligned> = unsafe {
/// FOWithVis::new(0)
/// };
/// }
///
/// unsafe impl GetFieldOffset<TS!(seat_size)> for Foo {
/// type Type = u128;
/// type Alignment = Unaligned;
/// type Privacy = IsPrivate;
///
/// const OFFSET_WITH_VIS: FOWithVis<Self, IsPrivate, TS!(seat_size), u128, Unaligned> =
/// unsafe{
/// <Self as GetFieldOffset<TS!(wheel_count)>>::OFFSET_WITH_VIS
/// .private_field_offset()
/// .next_field_offset()
/// .with_vis()
/// };
/// }
///
/// unsafe impl GetFieldOffset<TS!(is_automatic)> for Foo {
/// type Type = bool;
/// type Alignment = Aligned;
/// type Privacy = IsPublic;
///
/// const OFFSET_WITH_VIS: FOWithVis<Self, IsPublic, TS!(is_automatic), bool, Aligned> =
/// unsafe{
/// <Self as GetFieldOffset<TS!(seat_size)>>::OFFSET_WITH_VIS
/// .private_field_offset()
/// .next_field_offset()
/// .with_vis()
/// };
/// }
///
/// ```
///
/// [`FieldOffset`]: ../struct.FieldOffset.html
///
/// [`GetPubFieldOffset`]: ./trait.GetPubFieldOffset.html
///
/// [`OFF!`]: ../macro.OFF.html
/// [`off`]: ../macro.off.html
/// [`PUB_OFF!`]: ../macro.PUB_OFF.html
/// [`pub_off`]: ../macro.pub_off.html
///
///
///
pub unsafe
//////////////////////////////////////////////////////////////////////////////////
/// An alias of the [`GetFieldOffset`] trait for public fields.
///
/// # Example
///
/// Defining a generic method for all types that have `a`, and `c` fields
///
/// ```rust
/// use repr_offset::{
/// for_examples::ReprC,
/// get_field_offset::FieldType,
/// privacy::{IsPublic, IsPrivate},
/// tstr::TS,
/// pub_off,
/// Aligned, GetPubFieldOffset, ROExtAcc,
/// };
///
/// use std::fmt::Debug;
///
/// print_a_c(&ReprC{a: 10, b: 20, c: 30, d: 40 });
///
/// fn print_a_c<T>(this: &T)
/// where
/// T: GetPubFieldOffset<TS!(a), Alignment = Aligned>,
/// T: GetPubFieldOffset<TS!(b), Alignment = Aligned>,
/// FieldType<T, TS!(a)>: Debug,
/// FieldType<T, TS!(b)>: Debug,
/// {
/// println!("{:?}", this.f_get(pub_off!(a)));
/// println!("{:?}", this.f_get(pub_off!(b)));
///
/// # use repr_offset::get_field_offset::FieldAlignment;
/// # let _: FieldAlignment<T, TS!(a)> = Aligned;
/// # let _: FieldAlignment<T, TS!(b)> = Aligned;
/// }
///
/// ```
///
/// [`GetFieldOffset`]: ./trait.GetFieldOffset.html
//////////////////////////////////////////////////////////////////////////////////
// Hack to assert that a type implements GetPubFieldOffset,
// while getting the associated types from GetFieldOffset.
use AssertImplsGPFO;
//////////////////////////////////////////////////////////////////////////////////
/// Gets the type of a public field in the `GetPubFieldOffset<FN>` impl for `This`.
///
/// # Example
///
/// ```rust
/// use repr_offset::{
/// for_examples::ReprC,
/// tstr::TS,
/// FieldType,
/// };
///
/// type This = ReprC<u8, &'static str, Option<usize>, bool>;
///
/// let _: FieldType<This, TS!(a)> = 3_u8;
/// let _: FieldType<This, TS!(b)> = "hello";
/// let _: FieldType<This, TS!(c)> = Some(5_usize);
/// let _: FieldType<This, TS!(d)> = false;
///
/// ```
pub type FieldType<This, FN> = Type;
/// Gets the alignment of a public field in the `GetPubFieldOffset<FN>` impl for `This`.
///
/// # Example
///
/// ```rust
/// use repr_offset::{
/// get_field_offset::FieldAlignment,
/// for_examples::{ReprC, ReprPacked},
/// tstr::TS,
/// Aligned, Unaligned,
/// };
///
/// type Inner = ReprPacked<i16, i32, i64, i128>;
///
/// type This = ReprC<Inner, &'static str, Option<usize>, bool>;
///
/// // Fields directly inside a ReprC are all aligned.
/// let _: FieldAlignment<This, TS!(a)> = Aligned;
/// let _: FieldAlignment<This, TS!(b)> = Aligned;
/// let _: FieldAlignment<This, TS!(c)> = Aligned;
/// let _: FieldAlignment<This, TS!(d)> = Aligned;
///
/// // Fields inside a ReprPacked are all unaligned.
/// let _: FieldAlignment<This, TS!(a, a)> = Unaligned;
/// let _: FieldAlignment<This, TS!(a, b)> = Unaligned;
/// let _: FieldAlignment<This, TS!(a, c)> = Unaligned;
/// let _: FieldAlignment<This, TS!(a, d)> = Unaligned;
///
/// ```
pub type FieldAlignment<This, FN> = Alignment;
////////////////////////////////////////////////////////////////////////////////
/// Gets the type of a (potentially) private field in the `GetFieldOffset<FN>` impl for `This`.
///
/// # Warning
///
/// Because the field may be private this can break when asking for
/// the type of fields in types from external crates.
///
/// # Example
///
/// ```rust
/// use repr_offset::{
/// get_field_offset::PrivFieldType,
/// tstr::TS,
/// unsafe_struct_field_offsets,
/// };
///
/// use foo::Foo;
///
/// let _: PrivFieldType<Foo, TS!(x)> = 3_u8;
/// let _: PrivFieldType<Foo, TS!(y)> = 5_u16;
/// let _: PrivFieldType<Foo, TS!(z)> = 8_u32;
/// let _: PrivFieldType<Foo, TS!(w)> = 13_u64;
///
/// mod foo {
/// use super::*;
///
/// #[repr(C)]
/// pub struct Foo {
/// x: u8,
/// pub(super) y: u16,
/// pub(crate) z: u32,
/// pub w: u64,
/// }
///
/// repr_offset::unsafe_struct_field_offsets!{
/// alignment = repr_offset::Aligned,
///
/// impl[] Foo {
/// const OFFSET_X, x: u8;
/// pub(super) const OFFSET_Y, y: u16;
/// pub(crate) const OFFSET_Z, z: u32;
/// pub const OFFSET_W, w: u64;
/// }
/// }
/// }
///
/// ```
///
pub type PrivFieldType<This, FN> = Type;
/// Gets the alignment of a (potentially) private field in the `GetFieldOffset<FN>` impl for `This`.
///
/// # Warning
///
/// Because the field may be private this can break when asking for
/// the alignment of fields in types from external crates.
///
/// # Example
///
/// ```rust
/// use repr_offset::{
/// for_examples::ReprPacked,
/// get_field_offset::PrivFieldAlignment,
/// tstr::TS,
/// Aligned, Unaligned,
/// };
///
/// # fn main(){
/// // Fields in ReprC are all aligned
/// let _: PrivFieldAlignment<Foo, TS!(x)> = Aligned;
/// let _: PrivFieldAlignment<Foo, TS!(y)> = Aligned;
/// let _: PrivFieldAlignment<Foo, TS!(z)> = Aligned;
/// let _: PrivFieldAlignment<Foo, TS!(w)> = Aligned;
///
/// // Fields in ReprPacked are all unaligned
/// let _: PrivFieldAlignment<Foo, TS!(y, a)> = Unaligned;
/// let _: PrivFieldAlignment<Foo, TS!(y, b)> = Unaligned;
/// let _: PrivFieldAlignment<Foo, TS!(y, c)> = Unaligned;
/// let _: PrivFieldAlignment<Foo, TS!(y, d)> = Unaligned;
/// # }
///
/// mod foo {
/// use super::*;
///
/// type YField = ReprPacked<&'static str, &'static [u8], char, bool>;
///
/// #[repr(C)]
/// pub struct Foo {
/// x: u8,
/// pub(super) y: YField,
/// pub(crate) z: u32,
/// pub w: u64,
/// }
///
/// repr_offset::unsafe_struct_field_offsets!{
/// alignment = Aligned,
///
/// impl[] Foo {
/// const OFFSET_X, x: u8;
/// pub(super) const OFFSET_Y, y: YField;
/// pub(crate) const OFFSET_Z, z: u32;
/// pub const OFFSET_W, w: u64;
/// }
/// }
/// }
///
/// use foo::Foo;
///
///
/// ```
///
pub type PrivFieldAlignment<This, FN> = Alignment;
/// Gets the privacy of a field in the `GetFieldOffset<FN>` impl for `This`.
///
/// # Warning
///
/// Because the field may be private this can break when asking for
/// the privacy of fields in types from external crates.
///
/// # Example
///
/// ```rust
/// use repr_offset::{
/// get_field_offset::FieldPrivacy,
/// privacy::{IsPrivate, IsPublic},
/// tstr::TS,
/// Aligned,
/// };
///
/// let _: FieldPrivacy<Foo, TS!(x)> = IsPrivate;
/// let _: FieldPrivacy<Foo, TS!(y)> = IsPrivate;
/// let _: FieldPrivacy<Foo, TS!(z)> = IsPrivate;
/// let _: FieldPrivacy<Foo, TS!(w)> = IsPublic;
///
/// mod foo {
/// use super::*;
///
/// #[repr(C)]
/// pub struct Foo {
/// x: u8,
/// pub(super) y: u16,
/// pub(crate) z: u32,
/// pub w: u64,
/// }
///
/// repr_offset::unsafe_struct_field_offsets!{
/// alignment = repr_offset::Aligned,
///
/// impl[] Foo {
/// const OFFSET_X, x: u8;
/// pub(super) const OFFSET_Y, y: u16;
/// pub(crate) const OFFSET_Z, z: u32;
/// pub const OFFSET_W, w: u64;
/// }
/// }
/// }
///
/// use foo::Foo;
///
///
///
/// ```
///
pub type FieldPrivacy<This, FN> = Privacy;
//////////////////////////////////////////////////////////////////////////////////
/// A wrapper around a [`FieldOffset`], with a visibility type parameter
/// (whether the field is pub or not).
///
/// # Type parameters
///
/// `S`: The type that contains the field
///
/// `V`: The visibility of the field, either [`IsPrivate`] or [`IsPublic`].
///
/// `FN`: The name of the field, written using the `repr_offset::tstr::TS` macro,
/// written as `TS!(field_name)`.
///
/// `F`: The type of the field.
///
/// `A`: The alignment of the field inside of `S`, either [`Aligned`] or [`Unaligned`].
///
///
/// [`GetFieldOffset::OFFSET_WITH_VIS`]:
/// ./trait.GetFieldOffset.html#associatedconstant.OFFSET_WITH_VIS
///
/// [`FieldOffset`]: ../struct.FieldOffset.html
///
/// [`Aligned`]: ../alignment/struct.Aligned.html
/// [`Unaligned`]: ../alignment/struct.Unaligned.html
///
/// [`IsPublic`]: ../privacy/struct.IsPublic.html
/// [`IsPrivate`]: ../privacy/struct.IsPrivate.html
///
///
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////