1use core::fmt;
2use core::mem::size_of;
3
4#[repr(u8)]
6#[derive(Copy, Clone, PartialEq)]
7pub enum DataType {
8 UInt8 = 0,
10 UInt16 = 1,
12 UInt32 = 2,
14 UInt64 = 3,
16 Int8 = 4,
18 Int16 = 5,
20 Int32 = 6,
22 Int64 = 7,
24 Float32 = 8,
26 Float64 = 9,
28 Bool = 10,
30 Timestamp = 11,
32 String = 12,
34}
35
36impl DataType {
37 pub const fn size(&self) -> usize {
39 match self {
40 DataType::UInt8 => 1,
41 DataType::UInt16 => 2,
42 DataType::UInt32 => 4,
43 DataType::UInt64 => 8,
44 DataType::Int8 => 1,
45 DataType::Int16 => 2,
46 DataType::Int32 => 4,
47 DataType::Int64 => 8,
48 DataType::Float32 => 4,
49 DataType::Float64 => 8,
50 DataType::Bool => 1,
51 DataType::Timestamp => 8,
52 DataType::String => panic!("String size is variable at compile time"),
53 }
54 }
55
56 pub fn to_sql_type(&self, size: usize) -> &'static str {
58 match self {
59 DataType::UInt8 => "INTEGER",
61 DataType::UInt16 => "INTEGER",
62 DataType::UInt32 => "INTEGER",
63 DataType::UInt64 => "INTEGER",
64 DataType::Int8 => "INTEGER",
65 DataType::Int16 => "INTEGER",
66 DataType::Int32 => "INTEGER",
67 DataType::Int64 => "INTEGER",
68 DataType::Float32 => "REAL",
70 DataType::Float64 => "REAL",
71 DataType::Bool => "INTEGER",
73 DataType::Timestamp => "INTEGER",
75 DataType::String => "TEXT",
77 }
78 }
79}
80
81impl Default for DataType {
82 fn default() -> Self {
83 DataType::Int32
84 }
85}
86
87pub mod time_utils {
89 pub const fn seconds_to_millis(seconds: u64) -> u64 {
91 seconds * 1000
92 }
93
94 pub const fn millis_to_seconds(millis: u64) -> u64 {
96 millis / 1000
97 }
98
99 pub const fn micros_to_millis(micros: u64) -> u64 {
101 micros / 1000
102 }
103
104 pub const fn millis_to_micros(millis: u64) -> u64 {
106 millis * 1000
107 }
108
109 pub const fn nanos_to_millis(nanos: u64) -> u64 {
111 nanos / 1000000
112 }
113
114 pub const fn millis_to_nanos(millis: u64) -> u64 {
116 millis * 1000000
117 }
118
119 pub fn time_diff(start: u64, end: u64) -> u64 {
121 if end > start {
122 end - start
123 } else {
124 start - end
125 }
126 }
127
128 pub fn is_in_time_range(timestamp: u64, start: u64, end: u64) -> bool {
130 timestamp >= start && timestamp <= end
131 }
132
133 #[cfg(feature = "std")]
136 pub fn now_millis() -> u64 {
137 use std::time::{SystemTime, UNIX_EPOCH};
138 SystemTime::now()
139 .duration_since(UNIX_EPOCH)
140 .expect("Time went backwards")
141 .as_millis() as u64
142 }
143
144 #[cfg(feature = "std")]
147 pub fn now_micros() -> u64 {
148 use std::time::{SystemTime, UNIX_EPOCH};
149 SystemTime::now()
150 .duration_since(UNIX_EPOCH)
151 .expect("Time went backwards")
152 .as_micros() as u64
153 }
154}
155
156#[repr(C)]
158#[derive(Copy, Clone)]
159pub union Value {
160 pub u8: u8,
161 pub u16: u16,
162 pub u32: u32,
163 pub u64: u64,
164 pub i8: i8,
165 pub i16: i16,
166 pub i32: i32,
167 pub i64: i64,
168 pub float32: f32,
169 pub float64: f64,
170 pub bool: bool,
171 pub timestamp: u64,
172 pub string: [u8; MAX_STRING_LEN],
173}
174
175impl PartialEq for Value {
177 fn eq(&self, other: &Self) -> bool {
178 false
184 }
185}
186
187pub const MAX_STRING_LEN: usize = 64;
189
190#[repr(C)]
192#[derive(Copy, Clone)]
193pub struct FieldDef {
194 pub name: &'static str,
196 pub data_type: DataType,
198 pub size: usize,
200 pub offset: usize,
202 pub primary_key: bool,
204 pub not_null: bool,
206 pub unique: bool,
208 pub auto_increment: bool,
210}
211
212impl FieldDef {
213 pub fn constraints_to_sql(&self) -> alloc::string::String {
215 let mut constraints = alloc::string::String::new();
216
217 if self.primary_key {
218 constraints.push_str(" PRIMARY KEY");
219 }
220
221 if self.auto_increment {
222 constraints.push_str(" AUTO_INCREMENT");
223 }
224
225 if self.not_null {
226 constraints.push_str(" NOT NULL");
227 }
228
229 if self.unique && !self.primary_key {
230 constraints.push_str(" UNIQUE");
231 }
232
233 constraints
234 }
235}
236
237#[repr(u8)]
239#[derive(Copy, Clone, PartialEq, Debug)]
240pub enum IndexType {
241 Hash = 0,
243 SortedArray = 1,
245 BTree = 2,
247 TTree = 3,
249}
250
251#[derive(Copy, Clone)]
253pub struct TableDef {
254 pub id: u8,
256 pub name: &'static str,
258 pub fields: &'static [FieldDef],
260 pub primary_key: usize,
262 pub secondary_index: Option<usize>,
264 pub secondary_index_type: IndexType,
266 pub record_size: usize,
268 pub max_records: usize,
270}
271
272#[derive(Debug, PartialEq, Copy, Clone)]
274#[repr(u8)]
275pub enum RecordStatus {
276 Free = 0,
278 Used = 1,
280 Deleted = 2,
282}
283
284#[repr(u8)]
286pub enum LockType {
287 None = 0,
289 Shared = 1,
291 Exclusive = 2,
293}
294
295#[repr(C)]
297pub struct RecordHeader {
298 pub status: RecordStatus,
300 pub version: u16,
302 pub lock_type: LockType,
304 pub lock_owner: u32,
306 pub lock_count: u8,
308}
309
310impl RecordHeader {
311 pub const SIZE: usize = size_of::<Self>();
313}
314
315const _: () = {
317 assert!(size_of::<RecordStatus>() == 1);
318 assert!(size_of::<DataType>() == 1);
319};
320
321#[derive(Debug, PartialEq, Eq)]
323pub enum RemDbError {
324 OutOfMemory,
326 RecordNotFound,
328 DuplicateKey,
330 FieldNotFound,
332 TypeMismatch,
334 TransactionError,
336 ConfigError,
338 UnsupportedOperation,
340 FileIoError,
342 SnapshotFormatError,
344 Crc32Error,
346 LogFormatError,
348 LogRecordNotFound,
350 LogChecksumError,
352 LockConflict,
354 LockTimeout,
356 TableNotFound,
358 InvalidRecordSize,
360 InvalidSqlQuery,
362 InternalError,
364}
365
366impl fmt::Display for RemDbError {
367 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368 match self {
369 RemDbError::OutOfMemory => write!(f, "Out of memory"),
370 RemDbError::RecordNotFound => write!(f, "Record not found"),
371 RemDbError::DuplicateKey => write!(f, "Duplicate key"),
372 RemDbError::FieldNotFound => write!(f, "Field not found"),
373 RemDbError::TypeMismatch => write!(f, "Type mismatch"),
374 RemDbError::TransactionError => write!(f, "Transaction error"),
375 RemDbError::ConfigError => write!(f, "Config error"),
376 RemDbError::UnsupportedOperation => write!(f, "Unsupported operation"),
377 RemDbError::FileIoError => write!(f, "File I/O error"),
378 RemDbError::SnapshotFormatError => write!(f, "Snapshot format error"),
379 RemDbError::Crc32Error => write!(f, "CRC32 checksum error"),
380 RemDbError::LogFormatError => write!(f, "Log format error"),
381 RemDbError::LogRecordNotFound => write!(f, "Log record not found"),
382 RemDbError::LogChecksumError => write!(f, "Log checksum error"),
383 RemDbError::LockConflict => write!(f, "Lock conflict"),
384 RemDbError::LockTimeout => write!(f, "Lock timeout"),
385 RemDbError::TableNotFound => write!(f, "Table not found"),
386 RemDbError::InvalidRecordSize => write!(f, "Invalid record size"),
387 RemDbError::InvalidSqlQuery => write!(f, "Invalid SQL query"),
388 RemDbError::InternalError => write!(f, "Internal error"),
389 }
390 }
391}
392
393pub type Result<T> = core::result::Result<T, RemDbError>;