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
31 changes: 8 additions & 23 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,28 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.85.0"
components: clippy, rustfmt
- uses: DeterminateSystems/nix-installer-action@main

- uses: Swatinem/rust-cache@v2

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y pkg-config libssl-dev cmake clang llvm
- uses: DeterminateSystems/magic-nix-cache-action@main

- name: Check
run: cargo check --workspace
run: nix develop --command cargo check --workspace

- name: Clippy
run: cargo clippy --workspace -- -D warnings
run: nix develop --command cargo clippy --workspace -- -D warnings

- name: Format
run: cargo fmt --all -- --check
run: nix develop --command cargo fmt --all -- --check

test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.85.0"

- uses: Swatinem/rust-cache@v2
- uses: DeterminateSystems/nix-installer-action@main

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y pkg-config libssl-dev cmake clang llvm
- uses: DeterminateSystems/magic-nix-cache-action@main

- name: Test
run: cargo test --workspace
run: nix develop --command cargo test --workspace
143 changes: 58 additions & 85 deletions crates/pack-abi/src/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,114 +74,86 @@ impl TypeHash {

/// Hash for the `bool` type.
pub const HASH_BOOL: TypeHash = TypeHash::from_bytes([
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `u8` type.
pub const HASH_U8: TypeHash = TypeHash::from_bytes([
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `u16` type.
pub const HASH_U16: TypeHash = TypeHash::from_bytes([
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `u32` type.
pub const HASH_U32: TypeHash = TypeHash::from_bytes([
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `u64` type.
pub const HASH_U64: TypeHash = TypeHash::from_bytes([
0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `s8` type.
pub const HASH_S8: TypeHash = TypeHash::from_bytes([
0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `s16` type.
pub const HASH_S16: TypeHash = TypeHash::from_bytes([
0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `s32` type.
pub const HASH_S32: TypeHash = TypeHash::from_bytes([
0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `s64` type.
pub const HASH_S64: TypeHash = TypeHash::from_bytes([
0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `f32` type.
pub const HASH_F32: TypeHash = TypeHash::from_bytes([
0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `f64` type.
pub const HASH_F64: TypeHash = TypeHash::from_bytes([
0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `char` type.
pub const HASH_CHAR: TypeHash = TypeHash::from_bytes([
0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `string` type.
pub const HASH_STRING: TypeHash = TypeHash::from_bytes([
0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

/// Hash for the `flags` type.
pub const HASH_FLAGS: TypeHash = TypeHash::from_bytes([
0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

// ============================================================================
Expand Down Expand Up @@ -260,18 +232,12 @@ const TAG_INTERFACE: u8 = 0x17;

/// Hash a list type: `list<T>`.
pub fn hash_list(element: &TypeHash) -> TypeHash {
TypeHasher::new()
.tag(TAG_LIST)
.child(element)
.finish()
TypeHasher::new().tag(TAG_LIST).child(element).finish()
}

/// Hash an option type: `option<T>`.
pub fn hash_option(inner: &TypeHash) -> TypeHash {
TypeHasher::new()
.tag(TAG_OPTION)
.child(inner)
.finish()
TypeHasher::new().tag(TAG_OPTION).child(inner).finish()
}

/// Hash a result type: `result<T, E>`.
Expand All @@ -285,9 +251,7 @@ pub fn hash_result(ok: &TypeHash, err: &TypeHash) -> TypeHash {

/// Hash a tuple type: `tuple<T1, T2, ...>`.
pub fn hash_tuple(elements: &[TypeHash]) -> TypeHash {
let mut hasher = TypeHasher::new()
.tag(TAG_TUPLE)
.count(elements.len());
let mut hasher = TypeHasher::new().tag(TAG_TUPLE).count(elements.len());

for elem in elements {
hasher = hasher.child(elem);
Expand All @@ -299,9 +263,7 @@ pub fn hash_tuple(elements: &[TypeHash]) -> TypeHash {
/// Hash a record type (structural - name NOT included).
/// Fields should be in canonical order (sorted by name).
pub fn hash_record(fields: &[(&str, TypeHash)]) -> TypeHash {
let mut hasher = TypeHasher::new()
.tag(TAG_RECORD)
.count(fields.len());
let mut hasher = TypeHasher::new().tag(TAG_RECORD).count(fields.len());

for (name, type_hash) in fields {
hasher = hasher.string(name).child(type_hash);
Expand All @@ -313,9 +275,7 @@ pub fn hash_record(fields: &[(&str, TypeHash)]) -> TypeHash {
/// Hash a variant type (structural - name NOT included).
/// Cases should be in canonical order (sorted by name).
pub fn hash_variant(cases: &[(&str, Option<TypeHash>)]) -> TypeHash {
let mut hasher = TypeHasher::new()
.tag(TAG_VARIANT)
.count(cases.len());
let mut hasher = TypeHasher::new().tag(TAG_VARIANT).count(cases.len());

for (name, payload) in cases {
hasher = hasher.string(name);
Expand All @@ -333,9 +293,7 @@ pub fn hash_variant(cases: &[(&str, Option<TypeHash>)]) -> TypeHash {
/// Param names are NOT included (just types in order).
/// Result types are included in order.
pub fn hash_function(params: &[TypeHash], results: &[TypeHash]) -> TypeHash {
let mut hasher = TypeHasher::new()
.tag(TAG_FUNCTION)
.count(params.len());
let mut hasher = TypeHasher::new().tag(TAG_FUNCTION).count(params.len());

for param in params {
hasher = hasher.child(param);
Expand Down Expand Up @@ -390,10 +348,8 @@ pub fn hash_interface(
/// 2. This produces a "template hash"
/// 3. The template hash IS the final hash (self-reference is structural)
pub const HASH_SELF_REF: TypeHash = TypeHash::from_bytes([
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);

#[cfg(test)]
Expand All @@ -403,9 +359,20 @@ mod tests {
#[test]
fn test_primitive_hashes_are_unique() {
let primitives = [
HASH_BOOL, HASH_U8, HASH_U16, HASH_U32, HASH_U64,
HASH_S8, HASH_S16, HASH_S32, HASH_S64,
HASH_F32, HASH_F64, HASH_CHAR, HASH_STRING, HASH_FLAGS,
HASH_BOOL,
HASH_U8,
HASH_U16,
HASH_U32,
HASH_U64,
HASH_S8,
HASH_S16,
HASH_S32,
HASH_S64,
HASH_F32,
HASH_F64,
HASH_CHAR,
HASH_STRING,
HASH_FLAGS,
];

for (i, a) in primitives.iter().enumerate() {
Expand Down Expand Up @@ -465,13 +432,19 @@ mod tests {
let iface_a = hash_interface(
"math",
&[],
&[Binding { name: "add", hash: hash_function(&[HASH_S32], &[HASH_S32]) }],
&[Binding {
name: "add",
hash: hash_function(&[HASH_S32], &[HASH_S32]),
}],
);

let iface_b = hash_interface(
"math",
&[],
&[Binding { name: "inc", hash: hash_function(&[HASH_S32], &[HASH_S32]) }],
&[Binding {
name: "inc",
hash: hash_function(&[HASH_S32], &[HASH_S32]),
}],
);

// Different binding names = different interface hash
Expand Down
Loading
Loading