1use core::mem::{align_of, offset_of, size_of};
10
11use crate::volume;
12
13#[repr(C)]
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct FmfRow {
18 pub entry_ref: u64,
20 pub frn: u64,
22 pub size: u64,
24 pub mtime: i64,
26 pub name_off: u32,
28 pub parent_path_off: u32,
30 pub flags: u32,
32 pub name_len: u16,
34 pub parent_path_len: u16,
36}
37
38impl FmfRow {
39 pub const LEN: usize = size_of::<Self>();
41}
42
43const _: () = {
44 assert!(size_of::<FmfRow>() == 48);
45 assert!(align_of::<FmfRow>() == 8);
46 assert!(offset_of!(FmfRow, entry_ref) == 0);
47 assert!(offset_of!(FmfRow, frn) == 8);
48 assert!(offset_of!(FmfRow, size) == 16);
49 assert!(offset_of!(FmfRow, mtime) == 24);
50 assert!(offset_of!(FmfRow, name_off) == 32);
51 assert!(offset_of!(FmfRow, parent_path_off) == 36);
52 assert!(offset_of!(FmfRow, flags) == 40);
53 assert!(offset_of!(FmfRow, name_len) == 44);
54 assert!(offset_of!(FmfRow, parent_path_len) == 46);
55};
56
57#[repr(C)]
60pub struct FmfPage {
61 pub row_count: u32,
63 #[expect(clippy::pub_underscore_fields, reason = "C ABI padding/reserved field")]
65 pub _pad: u32,
66 pub rows: *const FmfRow,
68 pub blob: *const u8,
70 pub blob_len: u32,
72 #[expect(clippy::pub_underscore_fields, reason = "C ABI padding/reserved field")]
74 pub _pad2: u32,
75}
76
77const _: () = {
78 assert!(size_of::<FmfPage>() == 32);
79 assert!(align_of::<FmfPage>() == 8);
80 assert!(offset_of!(FmfPage, row_count) == 0);
81 assert!(offset_of!(FmfPage, rows) == 8);
82 assert!(offset_of!(FmfPage, blob) == 16);
83 assert!(offset_of!(FmfPage, blob_len) == 24);
84};
85
86#[repr(C)]
89pub struct FmfBlob {
90 pub data: *const u8,
92 pub len: u32,
94 #[expect(clippy::pub_underscore_fields, reason = "C ABI padding/reserved field")]
96 pub _pad: u32,
97}
98
99const _: () = {
100 assert!(size_of::<FmfBlob>() == 16);
101 assert!(align_of::<FmfBlob>() == 8);
102 assert!(offset_of!(FmfBlob, data) == 0);
103 assert!(offset_of!(FmfBlob, len) == 8);
104 assert!(offset_of!(FmfBlob, _pad) == 12);
105};
106
107#[repr(C)]
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub struct FmfEvent {
112 pub kind: u32,
114 #[expect(clippy::pub_underscore_fields, reason = "C ABI padding/reserved field")]
116 pub _pad: u32,
117 pub entries: u64,
119 pub volume: [u8; 16],
121}
122
123impl FmfEvent {
124 pub const LEN: usize = size_of::<Self>();
126
127 #[must_use]
129 pub fn new(kind: u32, entries: u64, volume: &str) -> Self {
130 Self {
131 kind,
132 _pad: 0,
133 entries,
134 volume: volume::encode_label(volume),
135 }
136 }
137
138 #[must_use]
140 pub fn volume_str(&self) -> &str {
141 volume::decode_label(&self.volume)
142 }
143}
144
145const _: () = {
146 assert!(size_of::<FmfEvent>() == 32);
147 assert!(align_of::<FmfEvent>() == 8);
148 assert!(offset_of!(FmfEvent, kind) == 0);
149 assert!(offset_of!(FmfEvent, _pad) == 4);
150 assert!(offset_of!(FmfEvent, entries) == 8);
151 assert!(offset_of!(FmfEvent, volume) == 16);
152};
153
154#[repr(C)]
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
158pub struct FmfQueryOptions {
159 pub sort: u32,
161 pub desc: u32,
163 pub case_mode: u32,
165 pub include_hidden_system: u32,
167 pub regex_mode: u32,
172}
173
174impl FmfQueryOptions {
175 pub const LEN: usize = size_of::<Self>();
177}
178
179const _: () = {
180 assert!(size_of::<FmfQueryOptions>() == 20);
181 assert!(align_of::<FmfQueryOptions>() == 4);
182 assert!(offset_of!(FmfQueryOptions, sort) == 0);
183 assert!(offset_of!(FmfQueryOptions, desc) == 4);
184 assert!(offset_of!(FmfQueryOptions, case_mode) == 8);
185 assert!(offset_of!(FmfQueryOptions, include_hidden_system) == 12);
186 assert!(offset_of!(FmfQueryOptions, regex_mode) == 16);
187};
188
189#[repr(C)]
191#[derive(Debug, Clone, Copy)]
192pub struct FmfVolumeStatus {
193 pub label: [u8; 16],
195 pub state: u32,
197 #[expect(clippy::pub_underscore_fields, reason = "C ABI padding/reserved field")]
199 pub _pad: u32,
200 pub entries: u64,
202}
203
204const _: () = {
205 assert!(size_of::<FmfVolumeStatus>() == 32);
206 assert!(align_of::<FmfVolumeStatus>() == 8);
207 assert!(offset_of!(FmfVolumeStatus, label) == 0);
208 assert!(offset_of!(FmfVolumeStatus, state) == 16);
209 assert!(offset_of!(FmfVolumeStatus, entries) == 24);
210};
211
212#[repr(C)]
216#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217pub struct FrameHeader {
218 pub len: u32,
220 pub opcode: u16,
222 pub flags: u16,
224 pub request_id: u32,
226 pub status: i32,
228}
229
230impl FrameHeader {
231 pub const LEN: usize = size_of::<Self>();
233
234 #[must_use]
236 pub fn to_bytes(self) -> [u8; Self::LEN] {
237 let mut b = [0u8; Self::LEN];
238 b[0..4].copy_from_slice(&self.len.to_le_bytes());
239 b[4..6].copy_from_slice(&self.opcode.to_le_bytes());
240 b[6..8].copy_from_slice(&self.flags.to_le_bytes());
241 b[8..12].copy_from_slice(&self.request_id.to_le_bytes());
242 b[12..16].copy_from_slice(&self.status.to_le_bytes());
243 b
244 }
245
246 #[must_use]
248 pub const fn from_bytes(b: &[u8; Self::LEN]) -> Self {
249 Self {
250 len: u32::from_le_bytes([b[0], b[1], b[2], b[3]]),
251 opcode: u16::from_le_bytes([b[4], b[5]]),
252 flags: u16::from_le_bytes([b[6], b[7]]),
253 request_id: u32::from_le_bytes([b[8], b[9], b[10], b[11]]),
254 status: i32::from_le_bytes([b[12], b[13], b[14], b[15]]),
255 }
256 }
257}
258
259const _: () = {
260 assert!(size_of::<FrameHeader>() == 16);
261 assert!(offset_of!(FrameHeader, len) == 0);
262 assert!(offset_of!(FrameHeader, opcode) == 4);
263 assert!(offset_of!(FrameHeader, flags) == 6);
264 assert!(offset_of!(FrameHeader, request_id) == 8);
265 assert!(offset_of!(FrameHeader, status) == 12);
266};