add Never type to allow foreign trait implementations

This is a newtype to workaround `sanakirja::Storable` not being
able to be implemented on `std::convert::Infallible` due to
"foreign trait on foreign type" rules.
This commit is contained in:
hinto.janai 2024-02-13 20:05:52 -05:00
parent ddce2fa70c
commit 034284808a
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
4 changed files with 42 additions and 11 deletions

View file

@ -71,7 +71,6 @@ pub struct DupKey<P, S> {
pub secondary: S,
}
//---------------------------------------------------------------------------------------------------- Impl
/// Implement `Key` on most primitive types.
///
/// `Key::DUPLICATE` is always `false`.
@ -85,12 +84,7 @@ macro_rules! impl_key {
impl Key for $t {
const DUPLICATE: bool = false;
type Primary = $t;
// This 0 variant enum is unconstructable,
// and "has the same role as the ! “never” type":
// <https://doc.rust-lang.org/std/convert/enum.Infallible.html#future-compatibility>.
//
// FIXME: Use the `!` type when stable.
type Secondary = std::convert::Infallible;
type Secondary = crate::never::Never;
#[inline(always)]
fn primary(self) -> Self::Primary {

View file

@ -254,6 +254,9 @@ pub use key::{DupKey, Key};
mod macros;
mod never;
pub(crate) use never::Never;
pub mod ops;
mod pod;

34
database/src/never.rs Normal file
View file

@ -0,0 +1,34 @@
//! The never `!` type, in stable Rust.
//---------------------------------------------------------------------------------------------------- Table
/// Unconstructable never `!` type.
///
/// This is just a newtype around [`Infallible`], it is needed
/// because `cuprate_database` needs to implement serialization
/// traits (even if not used) to satisfy traits bounds, but
/// we cannot implement a foreign trait (e.g [`sanakirja::Storable`])
/// on a foreign type ([`Infallible`]).
///
/// This needs to be a local type to `cuprate_database`,
/// so unfortunately it cannot be in `cuprate_helper`.
///
/// `Infallible` is a 0 variant enum that is unconstructable,
/// it "has the same role as the ! “never” type":
/// <https://doc.rust-lang.org/std/convert/enum.Infallible.html#future-compatibility>.
///
/// FIXME: Use the `!` type when stable.
#[derive(Debug)]
pub(crate) struct Never(std::convert::Infallible);
//---------------------------------------------------------------------------------------------------- Impl
cfg_if::cfg_if! {
if #[cfg(all(feature = "sanakirja", not(feature = "heed")))] {
impl sanakirja::Storable for Never {
type PageReferences = core::iter::Empty<u64>;
fn page_references(&self) -> Self::PageReferences {
unreachable!()
}
}
}
}

View file

@ -111,7 +111,7 @@ mod private {
impl<const N: usize> Sealed for [u8; N] {}
impl_sealed! {
std::convert::Infallible,
crate::never::Never,
Vec<u8>,
Box<[u8]>,
std::sync::Arc<[u8]>,
@ -133,10 +133,10 @@ mod private {
}
//---------------------------------------------------------------------------------------------------- Pod Impl (bytes)
// Implement for `Infallible`.
// This type is `!` and should never be constructable,
// Implement for `Never`.
// This type is never be constructable,
// so all these functions will just panic.
impl Pod for std::convert::Infallible {
impl Pod for crate::never::Never {
#[cold]
#[inline(never)]
fn as_bytes(&self) -> impl AsRef<[u8]> {