use super::macros::intermediate; use super::table_row::ITableRow; use crate::error::CustomError; use organic::types::StandardProperties; #[derive(Debug, Clone)] pub(crate) struct ITable { pub(crate) children: Vec, pub(crate) post_blank: organic::types::PostBlank, } intermediate!( ITable, &'orig organic::types::Table<'parse>, original, intermediate_context, { // Separate groups by lines, multiple contiguous lines are the same as one. // If there is only one group, it is a tbody. // If there are more than one group, the first is thead and the rest are tbody. let sections = group_into_sections(&original.children); let children = { let mut ret = Vec::new(); for obj in original.children.iter() { ret.push(ITableRow::new(intermediate_context.clone(), obj).await?); } ret }; Ok(ITable { children, post_blank: original.get_post_blank(), }) } ); enum GroupIntoSectionsState<'orig, 'parse> { NonSection, Section(Vec<&'orig organic::types::TableRow<'parse>>), } fn group_into_sections<'orig, 'parse>( rows: &'orig Vec>, ) -> Vec>> { let mut sections = Vec::new(); let mut rows = rows.into_iter(); let mut state = GroupIntoSectionsState::NonSection; loop { state = match (state, rows.next()) { (GroupIntoSectionsState::NonSection, None) => break, (GroupIntoSectionsState::NonSection, Some(row)) if row.children.is_empty() => { GroupIntoSectionsState::NonSection } (GroupIntoSectionsState::NonSection, Some(row)) => { GroupIntoSectionsState::Section(vec![row]) } (GroupIntoSectionsState::Section(section), None) => { sections.push(section); break; } (GroupIntoSectionsState::Section(section), Some(row)) if row.children.is_empty() => { sections.push(section); GroupIntoSectionsState::NonSection } (GroupIntoSectionsState::Section(mut section), Some(row)) => { section.push(row); GroupIntoSectionsState::Section(section) } } } sections }