Skip to main content

truthlinked_sdk/
storage.rs

1//! Storage slot abstraction for direct storage access.
2//!
3//! This module provides the `Slot` type for working with individual storage slots
4//! and helper functions for deriving storage keys.
5//!
6//! # Example
7//!
8//! ```ignore
9//! use truthlinked_sdk::storage::Slot;
10//!
11//! let slot = Slot::from_label("counter");
12//! slot.write_u64(42)?;
13//! let value = slot.read_u64()?;
14//! ```
15
16use crate::codec::Codec32;
17use crate::env;
18use crate::error::Result;
19use crate::hashing;
20
21/// A 32-byte storage slot identifier.
22#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
23pub struct Slot(pub [u8; 32]);
24
25impl Slot {
26    /// Creates a new slot from a 32-byte array.
27    pub const fn new(slot: [u8; 32]) -> Self {
28        Self(slot)
29    }
30
31    /// Creates a slot from a string label.
32    pub fn from_label(label: &str) -> Self {
33        Self(hashing::derive_slot(b"trth:sdk:slot", &[label.as_bytes()]))
34    }
35
36    /// Creates a derived slot from a namespace and parts.
37    pub fn derived(namespace: &[u8; 32], parts: &[&[u8]]) -> Self {
38        Self(hashing::derive_slot(namespace, parts))
39    }
40
41    /// Reads the raw 32-byte value from this slot.
42    pub fn read(self) -> Result<[u8; 32]> {
43        env::storage_read_32(&self.0)
44    }
45
46    /// Writes a raw 32-byte value to this slot.
47    pub fn write(self, value: &[u8; 32]) -> Result<()> {
48        env::storage_write_32(&self.0, value)
49    }
50
51    /// Writes a typed value implementing `Codec32`.
52    pub fn write_typed<T: Codec32>(self, value: &T) -> Result<()> {
53        let encoded = value.encode_32();
54        self.write(&encoded)
55    }
56
57    /// Reads a typed value implementing `Codec32`.
58    pub fn read_typed<T: Codec32>(self) -> Result<T> {
59        let raw = self.read()?;
60        T::decode_32(&raw)
61    }
62
63    /// Writes a `u64` value (little-endian).
64    pub fn write_u64(self, value: u64) -> Result<()> {
65        let mut bytes = [0u8; 32];
66        bytes[..8].copy_from_slice(&value.to_le_bytes());
67        self.write(&bytes)
68    }
69
70    /// Reads a `u64` value (little-endian).
71    pub fn read_u64(self) -> Result<u64> {
72        let bytes = self.read()?;
73        let mut out = [0u8; 8];
74        out.copy_from_slice(&bytes[..8]);
75        Ok(u64::from_le_bytes(out))
76    }
77
78    /// Writes a `u128` value (little-endian).
79    pub fn write_u128(self, value: u128) -> Result<()> {
80        let mut bytes = [0u8; 32];
81        bytes[..16].copy_from_slice(&value.to_le_bytes());
82        self.write(&bytes)
83    }
84
85    /// Reads a `u128` value (little-endian).
86    pub fn read_u128(self) -> Result<u128> {
87        let bytes = self.read()?;
88        let mut out = [0u8; 16];
89        out.copy_from_slice(&bytes[..16]);
90        Ok(u128::from_le_bytes(out))
91    }
92}
93
94/// Creates a namespace hash from a label.
95pub fn namespace(label: &str) -> [u8; 32] {
96    hashing::hash32(label.as_bytes())
97}
98
99/// Creates a slot for a namespace and key.
100pub fn slot_for(namespace: &[u8; 32], key: &[u8]) -> Slot {
101    Slot::derived(namespace, &[key])
102}
103
104/// Creates a slot for a namespace and multiple key parts.
105pub fn slot_for_parts(namespace: &[u8; 32], parts: &[&[u8]]) -> Slot {
106    Slot::derived(namespace, parts)
107}
108
109/// Macro for creating a `Slot` from a 32-byte array.
110#[macro_export]
111macro_rules! slot {
112    ($bytes:expr) => {{
113        $crate::storage::Slot::new($bytes)
114    }};
115}