Skip to main content

midnight_base_crypto/fab/
alignments.rs

1// This file is part of midnight-ledger.
2// Copyright (C) 2025 Midnight Foundation
3// SPDX-License-Identifier: Apache-2.0
4// Licensed under the Apache License, Version 2.0 (the "License");
5// You may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7// http://www.apache.org/licenses/LICENSE-2.0
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14//! This module defines traits for rust types that are *aligned* in the sense of
15//! field-aligned binary values.
16
17use crate::fab::{AlignedValue, AlignedValueSlice, Alignment, AlignmentAtom};
18use crate::hash::{HashOutput, PERSISTENT_HASH_BYTES as PHB};
19
20/// A type that has a static alignment, that is, one which is shared by all
21/// members of the type.
22pub trait Aligned {
23    /// Returns the alignment of this rust type.
24    fn alignment() -> Alignment;
25}
26
27/// A type that has a dynamic alignment, that is, an alignment that depends on
28/// the instance of this type presented.
29pub trait DynAligned {
30    /// Returns the alignment of this instance the given type.
31    fn dyn_alignment(&self) -> Alignment;
32}
33
34impl<T: Aligned> DynAligned for T {
35    fn dyn_alignment(&self) -> Alignment {
36        T::alignment()
37    }
38}
39
40macro_rules! tuple_aligned {
41    () => {
42        impl Aligned for () {
43            fn alignment() -> Alignment {
44                Alignment(Vec::new())
45            }
46        }
47    };
48    ($a:ident$(, $as:ident)*) => {
49        impl<$a: Aligned$(, $as: Aligned)*> Aligned for ($a$(, $as)* ,) {
50            fn alignment() -> Alignment {
51                Alignment::concat([&$a::alignment()$(, &$as::alignment())*])
52            }
53        }
54
55        tuple_aligned!($($as),*);
56    }
57}
58
59tuple_aligned!(A, B, C, D, E, F, G, H, I, J, K);
60
61macro_rules! fixed_bytes_aligned {
62    ($($ty:ty; $size:expr_2021),*) => {
63        $(
64            impl Aligned for $ty {
65                fn alignment() -> Alignment {
66                    Alignment::singleton(AlignmentAtom::Bytes { length: $size as u32 })
67                }
68            }
69        )*
70    }
71}
72
73fixed_bytes_aligned!(
74    HashOutput; PHB,
75    bool; 1,
76    u8; 1,
77    u16; 2,
78    u32; 4,
79    u64; 8,
80    u128; 16
81);
82
83impl<const N: usize> Aligned for [u8; N] {
84    fn alignment() -> Alignment {
85        Alignment::singleton(AlignmentAtom::Bytes { length: N as u32 })
86    }
87}
88
89impl Aligned for &[u8] {
90    fn alignment() -> Alignment {
91        Alignment::singleton(AlignmentAtom::Compress)
92    }
93}
94
95impl Aligned for Vec<u8> {
96    fn alignment() -> Alignment {
97        Alignment::singleton(AlignmentAtom::Compress)
98    }
99}
100
101impl<T: Aligned> Aligned for Option<T> {
102    fn alignment() -> Alignment {
103        Alignment::concat([&bool::alignment(), &T::alignment()])
104    }
105}
106
107impl Alignment {
108    /// The alignment of `Option<T>` for this `T`. Useful if an `Alignment` is
109    /// known, but a corresponding rust type *isn't*.
110    pub fn option_of(&self) -> Alignment {
111        Alignment::concat([&bool::alignment(), self])
112    }
113}
114
115impl DynAligned for AlignedValue {
116    fn dyn_alignment(&self) -> Alignment {
117        self.alignment.clone()
118    }
119}
120
121impl DynAligned for AlignedValueSlice<'_> {
122    fn dyn_alignment(&self) -> Alignment {
123        self.1.clone()
124    }
125}