cynos_binary/
schema_layout.rs1use super::BinaryDataType;
6use alloc::string::{String, ToString};
7use alloc::vec::Vec;
8use cynos_core::schema::Table;
9#[cfg(feature = "wasm")]
10use wasm_bindgen::prelude::*;
11
12#[derive(Debug, Clone)]
14pub struct ColumnLayout {
15 pub name: String,
17 pub data_type: BinaryDataType,
19 pub fixed_size: usize,
21 pub is_nullable: bool,
23 pub offset: usize,
25}
26
27#[cfg_attr(feature = "wasm", wasm_bindgen)]
29#[derive(Debug, Clone)]
30pub struct SchemaLayout {
31 columns: Vec<ColumnLayout>,
32 row_stride: usize,
34 null_mask_size: usize,
36}
37
38impl SchemaLayout {
39 pub fn new(columns: Vec<ColumnLayout>, row_stride: usize, null_mask_size: usize) -> Self {
41 Self {
42 columns,
43 row_stride,
44 null_mask_size,
45 }
46 }
47
48 pub fn from_schema(schema: &Table) -> Self {
50 let columns: Vec<ColumnLayout> = schema
51 .columns()
52 .iter()
53 .scan(0usize, |offset, col| {
54 let data_type = BinaryDataType::from(col.data_type());
55 let fixed_size = data_type.fixed_size();
56 let layout = ColumnLayout {
57 name: col.name().to_string(),
58 data_type,
59 fixed_size,
60 is_nullable: col.is_nullable(),
61 offset: *offset,
62 };
63 *offset += fixed_size;
64 Some(layout)
65 })
66 .collect();
67
68 let null_mask_size = (columns.len() + 7) / 8;
69 let data_size: usize = columns.iter().map(|c| c.fixed_size).sum();
70 let row_stride = null_mask_size + data_size;
71
72 Self {
73 columns,
74 row_stride,
75 null_mask_size,
76 }
77 }
78
79 pub fn from_schemas(schemas: &[&Table]) -> Self {
83 let columns: Vec<ColumnLayout> = schemas
84 .iter()
85 .enumerate()
86 .flat_map(|(table_idx, schema)| {
87 schema.columns().iter().map(move |col| (table_idx, col))
88 })
89 .scan(0usize, |offset, (table_idx, col)| {
90 let data_type = BinaryDataType::from(col.data_type());
91 let fixed_size = data_type.fixed_size();
92 let layout = ColumnLayout {
93 name: col.name().to_string(),
94 data_type,
95 fixed_size,
96 is_nullable: table_idx > 0 || col.is_nullable(),
98 offset: *offset,
99 };
100 *offset += fixed_size;
101 Some(layout)
102 })
103 .collect();
104
105 let null_mask_size = (columns.len() + 7) / 8;
106 let data_size: usize = columns.iter().map(|c| c.fixed_size).sum();
107 let row_stride = null_mask_size + data_size;
108
109 Self {
110 columns,
111 row_stride,
112 null_mask_size,
113 }
114 }
115
116 pub fn from_projection(schema: &Table, column_names: &[String]) -> Self {
118 let columns: Vec<ColumnLayout> = column_names
119 .iter()
120 .scan(0usize, |offset, name| {
121 let col = schema.get_column(name)?;
122 let data_type = BinaryDataType::from(col.data_type());
123 let fixed_size = data_type.fixed_size();
124 let layout = ColumnLayout {
125 name: col.name().to_string(),
126 data_type,
127 fixed_size,
128 is_nullable: col.is_nullable(),
129 offset: *offset,
130 };
131 *offset += fixed_size;
132 Some(layout)
133 })
134 .collect();
135
136 let null_mask_size = (columns.len() + 7) / 8;
137 let data_size: usize = columns.iter().map(|c| c.fixed_size).sum();
138 let row_stride = null_mask_size + data_size;
139
140 Self {
141 columns,
142 row_stride,
143 null_mask_size,
144 }
145 }
146
147 pub fn columns(&self) -> &[ColumnLayout] {
149 &self.columns
150 }
151
152 pub fn row_stride(&self) -> usize {
154 self.row_stride
155 }
156
157 pub fn null_mask_size(&self) -> usize {
159 self.null_mask_size
160 }
161
162 pub fn calculate_fixed_size(&self, row_count: usize) -> usize {
164 super::HEADER_SIZE + self.row_stride * row_count
165 }
166}
167
168#[cfg(feature = "wasm")]
170#[wasm_bindgen]
171impl SchemaLayout {
172 #[wasm_bindgen(js_name = columnCount)]
174 pub fn column_count_js(&self) -> usize {
175 self.columns.len()
176 }
177
178 #[wasm_bindgen(js_name = columnName)]
180 pub fn column_name_js(&self, idx: usize) -> Option<String> {
181 self.columns.get(idx).map(|c| c.name.clone())
182 }
183
184 #[wasm_bindgen(js_name = columnType)]
186 pub fn column_type_js(&self, idx: usize) -> Option<u8> {
187 self.columns.get(idx).map(|c| c.data_type as u8)
188 }
189
190 #[wasm_bindgen(js_name = columnOffset)]
192 pub fn column_offset_js(&self, idx: usize) -> Option<usize> {
193 self.columns.get(idx).map(|c| c.offset)
194 }
195
196 #[wasm_bindgen(js_name = columnFixedSize)]
198 pub fn column_fixed_size_js(&self, idx: usize) -> Option<usize> {
199 self.columns.get(idx).map(|c| c.fixed_size)
200 }
201
202 #[wasm_bindgen(js_name = columnNullable)]
204 pub fn column_nullable_js(&self, idx: usize) -> Option<bool> {
205 self.columns.get(idx).map(|c| c.is_nullable)
206 }
207
208 #[wasm_bindgen(js_name = rowStride)]
210 pub fn row_stride_js(&self) -> usize {
211 self.row_stride
212 }
213
214 #[wasm_bindgen(js_name = nullMaskSize)]
216 pub fn null_mask_size_js(&self) -> usize {
217 self.null_mask_size
218 }
219}