1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
//
// Copyright (c) 2023 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
//
// Contributors:
//   Pierre Avital, <pierre.avital@me.com>
//

//! The core of the [`stabby`](https://crates.io/crates/stabby) ABI.
//!
//! This crate is generally not meant to be used directly, but through the `stabby` crate.

#![deny(
    missing_docs,
    clippy::missing_panics_doc,
    clippy::missing_const_for_fn,
    clippy::missing_safety_doc,
    clippy::missing_errors_doc
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(stabby_nightly, feature(freeze))]

/// ABI-stable smart pointers and allocated data structures, with support for custom allocators.
pub mod alloc;
/// Extending [Non-Zero Types](core::num) to enable niches for other values than 0.
pub mod num;

pub use stabby_macros::{canary_suffixes, dynptr, export, import, stabby, vtable as vtmacro};
use typenum2::unsigned::Alignment;

use core::fmt::{Debug, Display};

/// A no-op that fails to compile if `T` isn't proven ABI-stable by stabby.
pub const fn assert_stable<T: IStable>() {}

/// An ABI-stable tuple.
#[crate::stabby]
#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
pub struct Tuple<A, B>(pub A, pub B);

/// Generate the [`IStable::REPORT`] and [`IStable::ID`] fields for an implementation of [`IStable`].
#[macro_export]
macro_rules! primitive_report {
    ($name: expr, $ty: ty) => {
        const REPORT: &'static $crate::report::TypeReport = &$crate::report::TypeReport {
            name: $crate::str::Str::new($name),
            module: $crate::str::Str::new(core::module_path!()),
            fields: $crate::StableLike::new(Some(&$crate::report::FieldReport {
                name: $crate::str::Str::new("inner"),
                ty: <$ty as $crate::IStable>::REPORT,
                next_field: $crate::StableLike::new(None),
            })),
            version: 0,
            tyty: $crate::report::TyTy::Struct,
        };
        const ID: u64 = $crate::report::gen_id(Self::REPORT);
    };
    ($name: expr) => {
        const REPORT: &'static $crate::report::TypeReport = &$crate::report::TypeReport {
            name: $crate::str::Str::new($name),
            module: $crate::str::Str::new(core::module_path!()),
            fields: $crate::StableLike::new(None),
            version: 0,
            tyty: $crate::report::TyTy::Struct,
        };
        const ID: u64 = $crate::report::gen_id(Self::REPORT);
    };
}

/// A support module for stabby's dark magic.
///
/// It implements basic arithmetics in the type system, and needs to be included in stabby for the ternaries
/// to keep trait bounds that are needed for proofs to work out.
pub mod typenum2;
use istable::{ISaturatingAdd, Saturator};
#[doc(hidden)]
pub use typenum2::*;

/// Fires a compile error if the layout of a type is deemed sub-optimal.
#[macro_export]
macro_rules! assert_optimal_layout {
    ($t: ty) => {
        const _: () = {
            assert!(<$t>::has_optimal_layout());
        };
    };
}
pub use crate::enums::IDeterminantProvider;
/// Helpers to treat ABI-stable types as if they were their unstable equivalents.
pub mod as_mut;
/// ABI-stable equivalents of iterators.
pub mod iter;

/// Provides access to a value _as if_ it were of another type.
///
/// This is done by the following process:
/// - memcopy `self` into `copy`
/// - convert `copy` into `target: ManuallyDrop<Target>`
/// - provide a guard that can `Deref` or `DerefMut` into `target`
/// - upon dropping the mutable guard, convert `target` and assing `target` to `self`
///
/// This is always safe for non-self-referencial types.
pub trait AccessAs {
    /// Provides immutable access to a type as if it were its ABI-unstable equivalent.
    fn ref_as<T: ?Sized>(&self) -> <Self as as_mut::IGuardRef<T>>::Guard<'_>
    where
        Self: as_mut::IGuardRef<T>;
    /// Provides mutable access to a type as if it were its ABI-unstable equivalent.
    fn mut_as<T: ?Sized>(&mut self) -> <Self as as_mut::IGuardMut<T>>::GuardMut<'_>
    where
        Self: as_mut::IGuardMut<T>;
}

pub use fatptr::*;
/// How stabby does multi-trait objects.
mod fatptr;

/// Closures, but ABI-stable
pub mod closure;
/// Futures, but ABI-stable
pub mod future;
mod stable_impls;
/// Support for vtables for multi-trait objects
pub mod vtable;

// #[allow(type_alias_bounds)]
// pub type Stable<Source: IStabilize> = Source::Stable;

/// A ZST that's only allowed to exist if its generic parameter is ABI-stable.
pub struct AssertStable<T: IStable>(pub core::marker::PhantomData<T>);
impl<T: IStable> AssertStable<T> {
    /// Proves that `T` is ABI-stable.
    pub const fn assert() -> Self {
        Self(core::marker::PhantomData)
    }
}

/// Lets you tell `stabby` that `T` has the same stable layout as `As`.
///
/// Lying about this link between `T` and `As` will cause UB if a `#[repr(stabby)]` enum transitively contains
/// a value of this type.
///
/// If you want to be safe when using this, use [`NoNiches`] with the correct size and alignment for your
/// type.
#[repr(C)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StableLike<T, As> {
    value: T,
    marker: core::marker::PhantomData<As>,
}
impl<T: Debug, As> Debug for StableLike<T, As> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        self.value.fmt(f)
    }
}
impl<T: Display, As> Display for StableLike<T, As> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        self.value.fmt(f)
    }
}
impl<T: Clone, As> Clone for StableLike<T, As> {
    fn clone(&self) -> Self {
        Self {
            value: self.value.clone(),
            marker: self.marker,
        }
    }
}
impl<T: Copy, As> Copy for StableLike<T, As> {}
trait ConstChecks {
    const CHECK: ();
}
impl<T, As: IStable> ConstChecks for StableLike<T, As> {
    const CHECK: () = {
        if core::mem::size_of::<T>() != <As::Size as Unsigned>::USIZE {
            panic!(
                "Attempted to construct `StableLike<T, As>` despite As::Size not matching T's size"
            )
        }
        if core::mem::align_of::<T>() != <As::Align as Unsigned>::USIZE {
            panic!(
                "Attempted to construct `StableLike<T, As>` despite As::Size not matching T's size"
            )
        }
    };
}
impl<T, As: IStable> StableLike<T, As> {
    /// Wraps a value in a type that provides information about its layout.
    ///
    /// Asserts that `T` and `As` have the same size and aligment at compile time,
    /// and relies on the user for the niche information to be correct.
    #[allow(clippy::let_unit_value)]
    pub const fn new(value: T) -> Self {
        _ = Self::CHECK;
        Self {
            value,
            marker: core::marker::PhantomData,
        }
    }
    /// Returns a reference to the underlying type
    /// # Safety
    /// This is only safe if `T` is FFI-safe, or if this `self` was constructed from a value
    /// of `T` that was instanciated within the same shared object.
    pub const unsafe fn as_ref_unchecked(&self) -> &T {
        &self.value
    }
    /// Returns a reference to the underlying type
    pub const fn as_ref(&self) -> &T
    where
        T: IStable,
    {
        &self.value
    }
    /// # Safety
    /// This is only safe if `T` is FFI-safe, or if this `self` was constructed from a value
    /// of `T` that was instanciated within the same shared object.
    pub unsafe fn as_mut_unchecked(&mut self) -> &mut T {
        &mut self.value
    }
    /// # Safety
    /// This is only safe if `T` is FFI-safe, or if this `self` was constructed from a value
    /// of `T` that was instanciated within the same shared object.
    pub unsafe fn into_inner_unchecked(self) -> T {
        self.value
    }
    /// Extracts the inner value from `self`
    pub fn into_inner(self) -> T
    where
        T: IStable,
    {
        self.value
    }
}

unsafe impl<T, As: IStable> IStable for StableLike<T, As> {
    type Size = As::Size;
    type Align = As::Align;
    type ForbiddenValues = As::ForbiddenValues;
    type UnusedBits = As::UnusedBits;
    type HasExactlyOneNiche = As::HasExactlyOneNiche;
    type ContainsIndirections = As::ContainsIndirections;
    const ID: u64 = crate::report::gen_id(Self::REPORT);
    const REPORT: &'static report::TypeReport = As::REPORT;
}

/// Emulates a type of size `Size` and alignment `Align`.
///
/// Note that this is not a ZST, and that you may pass [`B0`] or [`B1`] as the this generic parameter if you
/// want to inform `stabby` that the type it emulates has exactly zero or one niche respectively that the
/// compiler knows about. This information can be used by `stabby` to determine that `core::option::Option`s
/// transitively containing the emulated type are indeed ABI-stable.
pub struct NoNiches<
    Size: Unsigned,
    Align: Alignment,
    HasExactlyOneNiche: ISaturatingAdd = Saturator,
    ContainsIndirections: Bit = B0,
>(
    Size::Padding,
    core::marker::PhantomData<(Size, Align, HasExactlyOneNiche, ContainsIndirections)>,
);
unsafe impl<
        Size: Unsigned,
        Align: Alignment,
        HasExactlyOneNiche: ISaturatingAdd,
        ContainsIndirections: Bit,
    > IStable for NoNiches<Size, Align, HasExactlyOneNiche, ContainsIndirections>
{
    type Size = Size;
    type Align = Align;
    type ForbiddenValues = End;
    type UnusedBits = End;
    type HasExactlyOneNiche = HasExactlyOneNiche;
    type ContainsIndirections = ContainsIndirections;
    primitive_report!("NoNiches");
}

/// Allows removing the [`IStable`] implementation from `T` if `Cond` is not also ABI-stable.
///
/// This is typically used in combination with [`StableLike`], for example in vtables to mark function
/// pointers as stable only if all of their arguments are stable.
#[repr(C)]
pub struct StableIf<T, Cond> {
    /// The actual value
    pub value: T,
    marker: core::marker::PhantomData<Cond>,
}
impl<T: Clone, Cond> Clone for StableIf<T, Cond> {
    fn clone(&self) -> Self {
        Self {
            value: self.value.clone(),
            marker: self.marker,
        }
    }
}
impl<T: Copy, Cond> Copy for StableIf<T, Cond> {}
impl<T, Cond> StableIf<T, Cond> {
    /// # Safety
    /// Refer to type documentation
    pub const unsafe fn new(value: T) -> Self {
        Self {
            value,
            marker: core::marker::PhantomData,
        }
    }
}

impl<T, Cond> core::ops::Deref for StableIf<T, Cond> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.value
    }
}
impl<T, Cond> core::ops::DerefMut for StableIf<T, Cond> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.value
    }
}
unsafe impl<T: IStable, Cond: IStable> IStable for StableIf<T, Cond> {
    type Size = T::Size;
    type Align = T::Align;
    type ForbiddenValues = T::ForbiddenValues;
    type UnusedBits = T::UnusedBits;
    type HasExactlyOneNiche = T::HasExactlyOneNiche;
    type ContainsIndirections = T::ContainsIndirections;
    const REPORT: &'static report::TypeReport = T::REPORT;
    const ID: u64 = crate::report::gen_id(Self::REPORT);
}

/// Used by proc-macros to concatenate fields before wrapping them in a [`Struct`] to compute their layout.
#[repr(C)]
#[derive(Default, Clone, Copy)]
pub struct FieldPair<A, B>(core::marker::PhantomData<(A, B)>);
/// Used by proc-macros to ensure a list of fields gets the proper end padding.
#[repr(transparent)]
pub struct Struct<T>(T);

/// Used by [`crate::result::Result`]
#[repr(C)]
pub union Union<A, B> {
    /// The `ok` variant of the union.
    pub ok: core::mem::ManuallyDrop<A>,
    /// The `err` variant of the union.
    pub err: core::mem::ManuallyDrop<B>,
}
impl<A, B> Clone for Union<A, B> {
    fn clone(&self) -> Self {
        unsafe { core::ptr::read(self) }
    }
}

/// How `stabby` exposes symbols that must be checked through canaries or reflection before being accessed to prevent UB after linking ABI-incompatible functions.
pub mod checked_import;
/// ABI-stable compact sum types!
pub mod enums;
/// How stabby computes and generates padding to shift variants in enums
pub mod padding;
/// Like [`core::result::Result`], but ABI-stable with niche optimizations!
pub mod result;
pub use result::Result;
/// Like [`core::option::Option`], but ABI-stable with niche optimizations!
pub mod option;
pub use option::Option;
/// A very simple ABI-stable reflection framework.
pub mod report;
/// ABI-stable slices.
pub mod slice;
/// ABI-stable strs.
pub mod str;

pub use istable::{Array, End, IStable};

/// The heart of `stabby`: the [`IStable`] trait.
pub mod istable;

mod boundtests {
    #[crate::stabby]
    pub trait Test {
        extern "C" fn test(&self);
        extern "C" fn test2(&self);
    }
    #[crate::stabby]
    pub struct Test2 {
        a: usize,
        b: usize,
    }
}

/// Expands to [`unreachable!()`](core::unreachable) in debug builds or if `--cfg check_unreachable=true` has been set in the `RUST_FLAGS`, and to [`core::hint::unreachable_unchecked`] otherwise.
///
/// This lets the compiler take advantage of the fact that the code is unreachable in release builds, and optimize accordingly, while giving you the opportunity to double check this at runtime in case of doubts.
///
/// # Panics
/// This macro panics if the code is actually reachable in debug mode.
/// This would mean that release code would be UB!
///
/// # Safety
/// This macro is inherently unsafe, as it can cause UB in release mode if the code is actually reachable.
#[macro_export]
macro_rules! unreachable_unchecked {
    () => {
        if cfg!(any(debug_assertions, check_unreachable = "true")) {
            ::core::unreachable!()
        } else {
            ::core::hint::unreachable_unchecked()
        }
    };
}

/// Expands to [`assert!(condition)`](core::assert) in debug builds or if `--cfg check_unreachable=true` has been set in the `RUST_FLAGS`, and to [`if condition {core::hint::unreachable_unchecked()}`](core::hint::unreachable_unchecked) otherwise.
///
/// This lets the compiler take advantage of the fact that the condition is always true in release builds, and optimize accordingly, while giving you the opportunity to double check this at runtime in case of doubts.
///
/// # Panics
/// This macro panics if the code is actually false in debug mode.
/// This would mean that release code would be UB!
///
/// # Safety
/// This macro is inherently unsafe, as it can cause UB in release mode if the assertion can actually be false.
#[macro_export]
macro_rules! assert_unchecked {
    ($e: expr, $($t: tt)*) => {
        if cfg!(any(debug_assertions, check_unreachable = "true")) {
            ::core::assert!($e, $($t)*);
        } else {
            if !$e {
                ::core::hint::unreachable_unchecked();
            }
        }
    };
}

/// Expands to [`assert_eq`](core::assert_eq) in debug builds or if `--cfg check_unreachable=true` has been set in the `RUST_FLAGS`, and to [`if a != b {core::hint::unreachable_unchecked()}`](core::hint::unreachable_unchecked) otherwise.
///
/// This lets the compiler take advantage of the fact that the condition is always true in release builds, and optimize accordingly, while giving you the opportunity to double check this at runtime in case of doubts.
///
/// # Panics
/// This macro panics if the code is actually false in debug mode.
/// This would mean that release code would be UB!
///
/// # Safety
/// This macro is inherently unsafe, as it can cause UB in release mode if the assertion can actually be false.
#[macro_export]
macro_rules! assert_eq_unchecked {
    ($a: expr, $b: expr, $($t: tt)*) => {
        if cfg!(any(debug_assertions, check_unreachable = "true")) {
            ::core::assert_eq!($a, $b, $($t)*);
        } else {
            if $a != $b {
                ::core::hint::unreachable_unchecked();
            }
        }
    };
}