1use crate::ValueType;
2
3use super::{
4 column::ColumnMap,
5 convert::FormatConvertError,
6 legacy::LegacyTable,
7 modern::ModernTable,
8 private::{Column, Table},
9};
10
11pub type ModernTableBuilder<'b> = TableBuilderImpl<'b, ModernTable<'b>>;
13pub type LegacyTableBuilder<'b> = TableBuilderImpl<'b, LegacyTable<'b>>;
15
16#[doc(hidden)]
18pub struct TableBuilderImpl<'buf, T: Table<'buf>> {
19 pub(crate) name: T::Name,
20 pub(crate) columns: ColumnMap<T::BuilderColumn, <T::BuilderColumn as Column>::Name>,
21 pub(crate) base_id: T::Id,
22 pub(crate) rows: Vec<T::BuilderRow>,
23}
24
25impl<'b, T> TableBuilderImpl<'b, T>
26where
27 T: Table<'b>,
28{
29 pub fn with_name(name: impl Into<T::Name>) -> Self {
30 Self {
31 name: name.into(),
32 base_id: 1.into(), columns: ColumnMap::default(),
34 rows: vec![],
35 }
36 }
37
38 pub(crate) fn from_table(
39 name: T::Name,
40 base_id: T::Id,
41 columns: ColumnMap<T::BuilderColumn, <T::BuilderColumn as Column>::Name>,
42 rows: Vec<T::BuilderRow>,
43 ) -> Self {
44 Self {
45 name,
46 columns,
47 base_id,
48 rows,
49 }
50 }
51
52 pub fn add_column(mut self, column: impl Into<T::BuilderColumn>) -> Self {
53 self.columns.push(column.into());
54 self
55 }
56
57 pub fn add_row(mut self, row: impl Into<T::BuilderRow>) -> Self {
59 self.rows.push(row.into());
60 self
61 }
62
63 pub fn set_rows(mut self, rows: Vec<T::BuilderRow>) -> Self {
65 self.rows = rows;
66 self
67 }
68
69 pub fn set_columns(mut self, columns: impl IntoIterator<Item = T::BuilderColumn>) -> Self {
70 self.columns = columns.into_iter().collect();
71 self
72 }
73
74 pub fn set_base_id(mut self, base_id: T::Id) -> Self {
75 self.base_id = base_id;
76 self
77 }
78}
79
80impl<'b> ModernTableBuilder<'b> {
82 pub fn try_build(self) -> Result<ModernTable<'b>, FormatConvertError> {
83 let hash_col = self
86 .columns
87 .iter()
88 .position(|c| c.value_type == ValueType::HashRef);
89 let mut row_map: Vec<(u32, u32)> = hash_col
91 .map(|col_idx| {
92 self.rows
93 .iter()
94 .enumerate()
95 .map(|(i, row)| (row.values[col_idx].to_integer(), i as u32))
96 .collect()
97 })
98 .unwrap_or_default();
99 row_map.sort_unstable();
100 row_map.dedup_by_key(|(hash, _)| *hash);
101
102 Ok(ModernTable::new(self, row_map))
106 }
107
108 pub(crate) fn build_with_row_map(self, row_map: Vec<(u32, u32)>) -> ModernTable<'b> {
109 ModernTable::new(self, row_map)
110 }
111
112 pub fn build(self) -> ModernTable<'b> {
113 self.try_build().unwrap()
114 }
115}
116
117impl<'b> LegacyTableBuilder<'b> {
119 pub fn try_build(self) -> Result<LegacyTable<'b>, FormatConvertError> {
120 let rows =
121 u16::try_from(self.rows.len()).map_err(|_| FormatConvertError::MaxRowCountExceeded)?;
122 if self.base_id.checked_add(rows).is_none() {
123 return Err(FormatConvertError::UnsupportedRowId(u16::MAX as u32));
126 }
127 Ok(LegacyTable::new(self))
128 }
129
130 pub fn build(self) -> LegacyTable<'b> {
131 self.try_build().unwrap()
132 }
133}