ruda_runtime/runtime/storage/
base.rs1use crate::runtime::{memory_management::ManagedMemoryBinding, server::IoError, storage_id_type};
2use core::fmt::Debug;
3
4storage_id_type!(StorageId);
6
7impl core::fmt::Display for StorageId {
8 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
9 f.write_fmt(format_args!("StorageId({})", self.value))
10 }
11}
12
13#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct StorageUtilization {
16 pub offset: u64,
18 pub size: u64,
20}
21
22#[derive(new, Clone, Debug)]
24pub struct StorageHandle {
25 pub id: StorageId,
27 pub utilization: StorageUtilization,
29}
30
31impl StorageHandle {
32 pub fn size(&self) -> u64 {
38 self.utilization.size
39 }
40
41 pub fn offset(&self) -> u64 {
43 self.utilization.offset
44 }
45
46 pub fn offset_start(&self, offset_bytes: u64) -> Self {
48 let utilization = StorageUtilization {
49 offset: self.offset().checked_add(offset_bytes)
50 .expect("storage offset overflow"),
51 size: self.size().checked_sub(offset_bytes)
52 .expect("storage prefix exceeds resource size"),
53 };
54
55 Self {
56 id: self.id,
57 utilization,
58 }
59 }
60
61 pub fn offset_end(&self, offset_bytes: u64) -> Self {
63 let utilization = StorageUtilization {
64 offset: self.offset(),
65 size: self.size().checked_sub(offset_bytes)
66 .expect("storage suffix exceeds resource size"),
67 };
68
69 Self {
70 id: self.id,
71 utilization,
72 }
73 }
74}
75
76pub trait ComputeStorage: Send {
78 type Resource: Send;
81
82 fn alignment(&self) -> usize;
84
85 fn get(&mut self, handle: &StorageHandle) -> Self::Resource;
87
88 fn get_pinned(&mut self, handle: &StorageHandle, _binding: ManagedMemoryBinding) -> Self::Resource {
90 self.get(handle)
91 }
92
93 fn supports_relocation(&self) -> bool { false }
95
96 fn relocation_barrier(&mut self) -> Result<(), IoError> {
98 Err(IoError::UnsupportedIoOperation { backtrace: ruda_core::backtrace::BackTrace::capture() })
99 }
100
101 fn relocation_copy(&mut self, _source: &StorageHandle, _target: &StorageHandle) -> Result<(), IoError> {
103 Err(IoError::UnsupportedIoOperation { backtrace: ruda_core::backtrace::BackTrace::capture() })
104 }
105
106 fn relocation_copy_batch<'a>(
108 &mut self,
109 copies: impl IntoIterator<Item = (&'a StorageHandle, &'a StorageHandle)>,
110 ) -> Result<(), IoError>
111 where
112 Self: Sized,
113 {
114 for (source, target) in copies { self.relocation_copy(source, target)?; }
115 Ok(())
116 }
117
118 fn relocation_complete(&mut self) -> Result<(), IoError> {
120 self.relocation_barrier()
121 }
122
123 fn alloc(&mut self, size: u64) -> Result<StorageHandle, IoError>;
125
126 fn dealloc(&mut self, id: StorageId);
130
131 fn flush(&mut self);
133}
134
135#[derive(new, Debug)]
137pub struct ManagedResource<Resource: Send> {
138 #[allow(unused)]
142 binding: ManagedMemoryBinding,
143 resource: Resource,
144}
145
146impl<Resource: Send> ManagedResource<Resource> {
147 pub fn resource(&self) -> &Resource {
156 &self.resource
157 }
158}
159
160
161#[cfg(test)]
162mod handle_safety_tests {
163 use super::*;
164
165 #[test]
166 fn valid_handle_slicing_preserves_bounds() {
167 let handle = StorageHandle::new(StorageId::new(), StorageUtilization { offset: 8, size: 16 });
168 let sliced = handle.offset_start(4).offset_end(3);
169 assert_eq!(sliced.offset(), 12);
170 assert_eq!(sliced.size(), 9);
171 assert_eq!(handle.offset_start(16).size(), 0);
172 }
173
174 #[test]
175 #[should_panic(expected = "storage prefix exceeds resource size")]
176 fn oversized_prefix_never_wraps_in_release_mode() {
177 StorageHandle::new(StorageId::new(), StorageUtilization { offset: 0, size: 1 })
178 .offset_start(2);
179 }
180
181 #[test]
182 #[should_panic(expected = "storage suffix exceeds resource size")]
183 fn oversized_suffix_never_wraps_in_release_mode() {
184 StorageHandle::new(StorageId::new(), StorageUtilization { offset: 0, size: 1 })
185 .offset_end(2);
186 }
187
188 #[test]
189 #[should_panic(expected = "storage offset overflow")]
190 fn offset_overflow_never_wraps_in_release_mode() {
191 StorageHandle::new(StorageId::new(), StorageUtilization { offset: u64::MAX, size: 2 })
192 .offset_start(1);
193 }
194}