Skip to main content

kvbm_physical/manager/
handle.rs

1// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Layout handle type encoding worker ID and layout ID.
5
6use bincode::{Decode, Encode};
7use serde::{Deserialize, Serialize};
8
9/// Unique handle for a layout combining worker_id and layout_id.
10///
11/// The handle encodes:
12/// - Bits 0-63: worker_id (u64)
13/// - Bits 64-79: layout_id (u16)
14/// - Bits 80-127: Reserved (48 bits, currently unused)
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode, Serialize, Deserialize)]
16pub struct LayoutHandle(u128);
17
18impl LayoutHandle {
19    /// Create a new layout handle from worker_id and layout_id.
20    ///
21    /// # Arguments
22    /// * `worker_id` - Unique identifier for the worker (0-63 bits)
23    /// * `layout_id` - Layout identifier within the worker (64-79 bits)
24    pub fn new(worker_id: u64, layout_id: u16) -> Self {
25        let handle = (worker_id as u128) | ((layout_id as u128) << 64);
26        Self(handle)
27    }
28
29    /// Extract the worker_id from this handle.
30    pub fn worker_id(&self) -> u64 {
31        (self.0 & 0xFFFF_FFFF_FFFF_FFFF) as u64
32    }
33
34    /// Extract the layout_id from this handle.
35    pub fn layout_id(&self) -> u16 {
36        ((self.0 >> 64) & 0xFFFF) as u16
37    }
38
39    /// Get the raw u128 value.
40    pub fn as_u128(&self) -> u128 {
41        self.0
42    }
43
44    /// Reconstruct a handle from a raw u128 value.
45    ///
46    /// This preserves all bits including reserved bits, and is intended for
47    /// deserialization roundtrips with `as_u128()`.
48    pub fn from_u128(value: u128) -> Self {
49        Self(value)
50    }
51}
52
53impl std::fmt::Display for LayoutHandle {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        write!(
56            f,
57            "LayoutHandle(worker={}, layout={})",
58            self.worker_id(),
59            self.layout_id()
60        )
61    }
62}
63
64#[cfg(all(test, feature = "testing-kvbm"))]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn test_handle_encoding() {
70        let worker_id = 0x1234_5678_9ABC_DEF0u64;
71        let layout_id = 0x4242u16;
72
73        let handle = LayoutHandle::new(worker_id, layout_id);
74
75        assert_eq!(handle.worker_id(), worker_id);
76        assert_eq!(handle.layout_id(), layout_id);
77    }
78
79    #[test]
80    fn test_handle_roundtrip() {
81        let handle = LayoutHandle::new(42, 100);
82        let raw = handle.as_u128();
83        let restored = LayoutHandle::from_u128(raw);
84
85        assert_eq!(handle, restored);
86        assert_eq!(restored.worker_id(), 42);
87        assert_eq!(restored.layout_id(), 100);
88    }
89
90    #[test]
91    fn test_handle_max_values() {
92        let max_worker = u64::MAX;
93        let max_layout = u16::MAX;
94
95        let handle = LayoutHandle::new(max_worker, max_layout);
96
97        assert_eq!(handle.worker_id(), max_worker);
98        assert_eq!(handle.layout_id(), max_layout);
99    }
100
101    #[test]
102    fn test_handle_bincode_roundtrip() {
103        let handle = LayoutHandle::new(999, 42);
104
105        let encoded = bincode::encode_to_vec(handle, bincode::config::standard()).unwrap();
106        let (decoded, _): (LayoutHandle, _) =
107            bincode::decode_from_slice(&encoded, bincode::config::standard()).unwrap();
108
109        assert_eq!(handle, decoded);
110    }
111
112    #[test]
113    fn test_handle_display() {
114        let handle = LayoutHandle::new(123, 456);
115        let display = format!("{}", handle);
116        assert!(display.contains("123"));
117        assert!(display.contains("456"));
118    }
119}