From 034284808a84d97ff970d1252f64dcbf539b26a7 Mon Sep 17 00:00:00 2001 From: "hinto.janai" Date: Tue, 13 Feb 2024 20:05:52 -0500 Subject: [PATCH] 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. --- database/src/key.rs | 8 +------- database/src/lib.rs | 3 +++ database/src/never.rs | 34 ++++++++++++++++++++++++++++++++++ database/src/pod.rs | 8 ++++---- 4 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 database/src/never.rs diff --git a/database/src/key.rs b/database/src/key.rs index 69beff0d..4adb6cd7 100644 --- a/database/src/key.rs +++ b/database/src/key.rs @@ -71,7 +71,6 @@ pub struct DupKey { 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": - // . - // - // FIXME: Use the `!` type when stable. - type Secondary = std::convert::Infallible; + type Secondary = crate::never::Never; #[inline(always)] fn primary(self) -> Self::Primary { diff --git a/database/src/lib.rs b/database/src/lib.rs index db23a49a..31dee852 100644 --- a/database/src/lib.rs +++ b/database/src/lib.rs @@ -254,6 +254,9 @@ pub use key::{DupKey, Key}; mod macros; +mod never; +pub(crate) use never::Never; + pub mod ops; mod pod; diff --git a/database/src/never.rs b/database/src/never.rs new file mode 100644 index 00000000..fd9325f6 --- /dev/null +++ b/database/src/never.rs @@ -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": +/// . +/// +/// 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; + + fn page_references(&self) -> Self::PageReferences { + unreachable!() + } + } + } +} diff --git a/database/src/pod.rs b/database/src/pod.rs index b7c1ed7d..3ce55e16 100644 --- a/database/src/pod.rs +++ b/database/src/pod.rs @@ -111,7 +111,7 @@ mod private { impl Sealed for [u8; N] {} impl_sealed! { - std::convert::Infallible, + crate::never::Never, Vec, 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]> {