Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ tracing = "0.1.37"
tracing-subscriber = "0.3.16"
triomphe = { git = "https://github.com/sokra/triomphe", branch = "sokra/unstable" }
unsize = "1.1.0"
unty = "0.0.4"
url = "2.2.2"
urlencoding = "2.1.2"
uuid = "1.18.1"
Expand Down
1 change: 1 addition & 0 deletions turbopack/crates/turbo-bincode/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ ringmap = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
smallvec = { workspace = true }
unty = { workspace = true }
54 changes: 54 additions & 0 deletions turbopack/crates/turbo-bincode/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[doc(hidden)]
pub mod macro_helpers;

use std::ptr::copy_nonoverlapping;

use ::smallvec::SmallVec;
Expand Down Expand Up @@ -115,6 +118,57 @@ impl Reader for TurboBincodeReader<'_> {
}
}

/// Represents a type that can only be encoded with a [`TurboBincodeEncoder`].
///
/// All traits implementing this must also implement the more generic [`Encode`] trait, but they
/// should panic if any other encoder is used.
///
/// Use [`impl_encode_for_turbo_bincode_encode`] to automatically implement the [`Encode`] trait
/// from this one.
pub trait TurboBincodeEncode: Encode {
fn encode(&self, encoder: &mut TurboBincodeEncoder) -> Result<(), EncodeError>;
Comment thread
bgw marked this conversation as resolved.
}

/// Represents a type that can only be decoded with a [`TurboBincodeDecoder`] and an empty `()`
/// context.
///
/// All traits implementing this must also implement the more generic [`Decode`] trait, but they
/// should panic if any other encoder is used.
///
/// Use [`impl_decode_for_turbo_bincode_decode`] to automatically implement the [`Decode`] trait
/// from this one.
pub trait TurboBincodeDecode<Context>: Decode<Context> {
fn decode(decoder: &mut TurboBincodeDecoder) -> Result<Self, DecodeError>;
}

#[macro_export]
macro_rules! impl_encode_for_turbo_bincode_encode {
($ty:ty) => {
impl $crate::macro_helpers::bincode::Encode for $ty {
fn encode<'a, E: $crate::macro_helpers::bincode::enc::Encoder>(
&self,
encoder: &'a mut E,
) -> ::std::result::Result<(), $crate::macro_helpers::bincode::error::EncodeError> {
$crate::macro_helpers::encode_for_turbo_bincode_encode_impl(self, encoder)
}
}
};
}

#[macro_export]
macro_rules! impl_decode_for_turbo_bincode_decode {
($ty:ty) => {
impl<Context> $crate::macro_helpers::bincode::Decode<Context> for $ty {
fn decode<D: $crate::macro_helpers::bincode::de::Decoder<Context = Context>>(
decoder: &mut D,
) -> ::std::result::Result<Self, $crate::macro_helpers::bincode::error::DecodeError>
{
$crate::macro_helpers::decode_for_turbo_bincode_decode_impl(decoder)
}
}
};
}

pub mod indexmap {
use std::hash::{BuildHasher, Hash};

Expand Down
62 changes: 62 additions & 0 deletions turbopack/crates/turbo-bincode/src/macro_helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::{any::type_name, mem::transmute};

pub use bincode;
use bincode::{
de::Decoder,
enc::Encoder,
error::{DecodeError, EncodeError},
};

use crate::{TurboBincodeDecode, TurboBincodeDecoder, TurboBincodeEncode, TurboBincodeEncoder};

Comment on lines +1 to +11
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unty crate is used in the module but never imported, causing compilation failures when unty::type_equal is called.

View Details
📝 Patch Details
diff --git a/turbopack/crates/turbo-bincode/src/macro_helpers.rs b/turbopack/crates/turbo-bincode/src/macro_helpers.rs
index ad0c624f7e..3286fa030a 100644
--- a/turbopack/crates/turbo-bincode/src/macro_helpers.rs
+++ b/turbopack/crates/turbo-bincode/src/macro_helpers.rs
@@ -6,6 +6,7 @@ use bincode::{
     enc::Encoder,
     error::{DecodeError, EncodeError},
 };
+use unty;
 
 use crate::{TurboBincodeDecode, TurboBincodeDecoder, TurboBincodeEncode, TurboBincodeEncoder};
 

Analysis

Missing unty crate import in macro_helpers.rs

What fails: Functions encode_for_turbo_bincode_encode_impl() (line 17) and decode_for_turbo_bincode_decode_impl() (line 50) in turbopack/crates/turbo-bincode/src/macro_helpers.rs call unty::type_equal::<...>() without importing the unty crate, causing compilation error E0433: failed to resolve: use of unresolved module or unlinked crate 'unty'

How to reproduce:

cd turbopack
cargo check -p turbo-bincode --lib

Or with rustc directly:

rustc --crate-type lib turbopack/crates/turbo-bincode/src/macro_helpers.rs --edition 2024

Result: Compilation fails with:

error[E0433]: failed to resolve: use of unresolved module or unlinked crate `unty`
 --> turbopack/crates/turbo-bincode/src/macro_helpers.rs:17:22
  |
17 |     let encoder = if unty::type_equal::<E, TurboBincodeEncoder>() {
   |                      ^^^^ use of unresolved module or unlinked crate `unty`

Expected: Should compile successfully. The unty crate is available in Cargo.toml as a dependency (confirmed in turbo-bincode/Cargo.toml), but requires explicit import per Rust language rules for external crates. The import statement use unty; has been added to resolve the issue.

#[track_caller]
pub fn encode_for_turbo_bincode_encode_impl<'a, T: TurboBincodeEncode, E: Encoder>(
value: &T,
encoder: &'a mut E,
) -> Result<(), EncodeError> {
let encoder = if unty::type_equal::<E, TurboBincodeEncoder>() {
// SAFETY: Transmute is safe because `&mut E` is `&mut TurboBincodeEncoder`:
// - `unty::type_equal::<E, TurboBincodeEncoder>()` does not check lifetimes, but does check
// the type and layout, so we know those are correct.
// - The transmuted encoder cannot escape this function, and we know that the lifetime of
// `'a` is at least as long as the function.
// - Lifetimes don't change layout. This is not strictly guaranteed, but if this assumption
// is broken, we'd have a different type id (type ids are derived from layout
// information), `type_equal` would return `false`, and we'd panic instead of violating
// memory safety.
// - Two mutable references have the same layout and alignment when they reference exactly
// the same type.
// - The explicit lifetime ('a) avoids creating an implitly unbounded lifetime.
unsafe { transmute::<&'a mut E, &'a mut TurboBincodeEncoder>(encoder) }
} else {
unreachable!(
"{} implements TurboBincodeEncode, but was called with a {} encoder implementation",
type_name::<T>(),
type_name::<E>(),
)
};
TurboBincodeEncode::encode(value, encoder)
}

#[track_caller]
pub fn decode_for_turbo_bincode_decode_impl<
'a,
Context,
T: TurboBincodeDecode<Context>,
D: Decoder<Context = Context>,
>(
decoder: &'a mut D,
) -> Result<T, DecodeError> {
let decoder = if unty::type_equal::<D, TurboBincodeDecoder>() {
// SAFETY: See notes on the `Encode::encode` implementation on
// `encode_for_turbo_bincode_encode_impl`.
unsafe { transmute::<&'a mut D, &'a mut TurboBincodeDecoder<'a>>(decoder) }
} else {
unreachable!(
"{} implements TurboBincodeDecode, but was called with a {} decoder implementation",
type_name::<T>(),
type_name::<D>(),
)
};
TurboBincodeDecode::decode(decoder)
}
Loading