/// output document, but we'd need more special cases instead of just using
/// the existing support for group items.
pub fn new_root() -> Self {
- Self::new(Details::Group(Vec::new())).with_label(Some(String::from("Output")))
+ Self::new(Details::Group(Heading(Vec::new()))).with_label(Some(String::from("Output")))
}
pub fn label(&self) -> Cow<'static, str> {
}
}
+#[derive(Clone, Debug, Serialize)]
+pub struct Heading(pub Vec<Arc<Item>>);
+
#[derive(Clone, Debug, Serialize)]
pub enum Details {
Chart,
Image,
- Group(Vec<Arc<Item>>),
+ Group(Heading),
Message(Box<Diagnostic>),
PageBreak,
Table(Box<PivotTable>),
}
impl Details {
+ pub fn into_item(self) -> Item {
+ Item::new(self)
+ }
+
pub fn as_group(&self) -> Option<&[Arc<Item>]> {
match self {
- Self::Group(children) => Some(children.as_slice()),
+ Self::Group(heading) => Some(heading.0.as_slice()),
_ => None,
}
}
pub fn as_mut_group(&mut self) -> Option<&mut Vec<Arc<Item>>> {
match self {
- Self::Group(children) => Some(children),
+ Self::Group(heading) => Some(&mut heading.0),
_ => None,
}
}
pub fn children(&self) -> impl Iterator<Item = &Arc<Item>> {
match self {
- Self::Group(children) => Some(children.iter()),
+ Self::Group(children) => Some(children.0.iter()),
_ => None,
}
.into_iter()
where
T: IntoIterator<Item = A>,
{
- Self::Group(iter.into_iter().map(|value| value.into()).collect())
+ Self::Group(Heading(
+ iter.into_iter().map(|value| value.into()).collect(),
+ ))
}
}
let Some(cur) = self.cur.take() else {
return;
};
- match cur.details {
- Details::Group(ref children) if !children.is_empty() => {
- self.cur = Some(children[0].clone());
- self.stack.push((cur, 1));
- }
- _ => {
- while let Some((item, index)) = self.stack.pop() {
- let children = item.details.as_group().unwrap();
- if index < children.len() {
- self.cur = Some(children[index].clone());
- self.stack.push((item, index + 1));
- return;
- }
+ if let Some(children) = cur.details.as_group()
+ && let Some(first_child) = children.first()
+ {
+ self.cur = Some(first_child.clone());
+ self.stack.push((cur, 1));
+ } else {
+ while let Some((item, index)) = self.stack.pop() {
+ let children = item.details.as_group().unwrap();
+ if index < children.len() {
+ self.cur = Some(children[index].clone());
+ self.stack.push((item, index + 1));
+ return;
}
}
}
fn flatten_children<'a>(
children: Vec<&'a Item>,
depth: usize,
- items: &mut Vec<&'a Item>,
- depths: &mut Vec<usize>,
+ items: &mut Vec<(&'a Item, usize)>,
) {
for child in children {
- flatten(child, depth, items, depths);
+ flatten(child, depth, items);
}
}
- fn flatten<'a>(
- item: &'a Item,
- depth: usize,
- items: &mut Vec<&'a Item>,
- depths: &mut Vec<usize>,
- ) {
+ fn flatten<'a>(item: &'a Item, depth: usize, items: &mut Vec<(&'a Item, usize)>) {
let children = take_children(item);
- items.push(item);
- depths.push(depth);
- flatten_children(children, depth + 1, items, depths);
+ items.push((item, depth));
+ flatten_children(children, depth + 1, items);
}
- fn select_matches(
- items: &[&Item],
- depths: &[usize],
- selection: &Selection,
- include: &mut BitVec,
- ) {
+ fn select_matches(items: &[(&Item, usize)], selection: &Selection, include: &mut BitVec) {
let mut instance_within_command = 0;
let mut last_instance = None;
let mut command_item = None;
let mut command_command_item = None;
let mut nth_command = 0;
- for (index, (item, depth)) in std::iter::zip(items, depths).enumerate() {
+ for (index, (item, depth)) in items.into_iter().enumerate() {
if *depth == 0 {
command_item = Some(index);
if let Some(last_instance) = last_instance.take() {
}
let mut items = Vec::new();
- let mut depths = Vec::new();
- flatten_children(take_children(&item), 0, &mut items, &mut depths);
+ flatten_children(take_children(&item), 0, &mut items);
let mut include = BitVec::from_elem(items.len(), false);
let selections = if self.0.is_empty() {
self.0.as_slice()
};
for selection in selections {
- select_matches(&items, &depths, selection, &mut include);
+ select_matches(&items, selection, &mut include);
}
let mut output = Item::new_root();
}
);
}
+
+ #[test]
+ fn apply_criteria() {
+ //let item = Details::Group();
+ todo!()
+ }
}
.write_inner_content(|w| {
w.create_element("label")
.write_text_content(BytesText::new(&item.label()))?;
- for child in children {
- self.write_item(child, w);
+ for child in &children.0 {
+ self.write_item(&child, w);
}
Ok(())
})
Details::Chart => todo!(),
Details::Image => todo!(),
Details::Group(children) => {
- for (index, child) in children.iter().enumerate() {
+ for (index, child) in children.0.iter().enumerate() {
if index > 0 {
writeln!(writer)?;
}
use enum_map::EnumMap;
use crate::output::{
- Details, Item,
+ Details,
drivers::{
Driver,
cairo::{CairoConfig, CairoDriver},
format!("{name} actual"),
);
- let item = Arc::new(Item::new(Details::Table(Box::new(pivot_table.clone()))));
+ let item = Arc::new(Details::Table(Box::new(pivot_table.clone())).into_item());
if let Some(dir) = std::env::var_os("PSPP_TEST_HTML_DIR") {
let writer = File::create(Path::new(&dir).join(name).with_extension("html")).unwrap();
HtmlDriver::for_writer(writer).write(&item);
}
- let item = Arc::new(Item::new(Details::Table(Box::new(pivot_table.clone()))));
+ let item = Arc::new(Details::Table(Box::new(pivot_table.clone())).into_item());
if let Some(dir) = std::env::var_os("PSPP_TEST_PDF_DIR") {
let config = CairoConfig::new(Path::new(&dir).join(name).with_extension("pdf"));
CairoDriver::new(&config).unwrap().write(&item);
use binrw::BinRead;
use displaydoc::Display;
-use itertools::Itertools;
use serde::Deserialize;
use zip::{ZipArchive, result::ZipError};
}
Ok((
- Item::new(Details::Group(items.into_iter().map_into().collect())),
+ items.into_iter().collect::<Details>().into_item(),
page_setup,
))
}
HeadingContent::Container(container) => {
if container.page_break_before {
items.push(
- Item::new(Details::PageBreak)
+ Details::PageBreak
+ .into_item()
.with_spv_info(SpvInfo::new(structure_member)),
);
}
}
ContainerContent::Text(container_text) => {
items.push(
- Item::new(Details::Text(Box::new(Text::new_log(
- container_text.decode(),
- ))))
- .with_command_name(container_text.command_name)
- .with_spv_info(SpvInfo::new(structure_member)),
+ Details::Text(Box::new(Text::new_log(container_text.decode())))
+ .into_item()
+ .with_command_name(container_text.command_name)
+ .with_spv_info(SpvInfo::new(structure_member)),
);
}
}
HeadingContent::Heading(heading) => {
let show = !heading.visibility.is_some();
items.push(
- Item::new(Details::Group(
- heading
- .decode(archive, structure_member)?
- .into_iter()
- .map_into()
- .collect(),
- ))
- .with_show(show)
- .with_spv_info(SpvInfo::new(structure_member)),
+ heading
+ .decode(archive, structure_member)?
+ .into_iter()
+ .collect::<Details>()
+ .into_item()
+ .with_show(show)
+ .with_spv_info(SpvInfo::new(structure_member)),
);
}
}
let table = LightTable::read(&mut Cursor::new(data))?;
let pivot_table = table.decode()?;
println!("{}", &pivot_table);
- Ok(
- Item::new(Details::Table(Box::new(pivot_table))).with_spv_info(
+ Ok(Details::Table(Box::new(pivot_table))
+ .into_item()
+ .with_spv_info(
SpvInfo::new(structure_member)
.with_members(SpvMembers::Light(self.table_structure.data_path.clone())),
- ),
- )
+ ))
} else {
todo!()
}
output.push(PivotTable::from(&metadata).into());
output.extend(dictionary.all_pivot_tables().into_iter().map_into());
output.extend(cases_to_output(&dictionary, cases));
- Item::new(Details::Group(output.into_iter().map_into().collect()))
+ output.into_iter().collect::<Details>().into_item()
}
- Err(error) => Item::new(Details::Text(Box::new(Text::new_log(error.to_string())))),
+ Err(error) => Details::Text(Box::new(Text::new_log(error.to_string()))).into_item(),
};
let actual = output.to_string();
output.push(PivotTable::from(&metadata).into());
output.extend(dictionary.all_pivot_tables().into_iter().map_into());
output.extend(cases_to_output(&dictionary, cases));
- Item::new(Details::Group(output.into_iter().map_into().collect()))
+ output.into_iter().collect::<Details>().into_item()
}
- Err(error) => Item::new(Details::Text(Box::new(Text::new_log(error.to_string())))),
+ Err(error) => Details::Text(Box::new(Text::new_log(error.to_string()))).into_item(),
};
let actual = output.to_string();
use anyhow::{Result, anyhow};
use clap::{Args, ValueEnum};
use encoding_rs::Encoding;
+use itertools::Itertools;
use pspp::{
data::cases_to_output,
output::{
}
impl Output {
- /*
- fn show_metadata(&self, metadata: MetadataEntry) -> Result<()> {
- match self {
- Self::Driver { driver, .. } => {
- driver
- .borrow_mut()
- .write(&Arc::new(Item::new(metadata.into_pivot_table())));
- Ok(())
- }
- Self::Json { .. } => self.show_json(&metadata),
- Self::Discard => Ok(()),
- }
- }*/
-
fn show<T>(&self, value: &T) -> Result<()>
where
T: Serialize,
Self::Driver { driver, .. } => {
driver
.borrow_mut()
- .write(&Arc::new(Item::new(value.into())));
+ .write(&Arc::new(value.into().into_item()));
Ok(())
}
Self::Json { .. } => self.show_json(value),
match &output {
Output::Driver { driver, mode: _ } => {
let mut output = Vec::new();
- output.push(Item::new(PivotTable::from(&metadata)));
- output.extend(
- dictionary
- .all_pivot_tables()
- .into_iter()
- .map(|pivot_table| Item::new(pivot_table)),
- );
+ output.push(PivotTable::from(&metadata).into());
+ output.extend(dictionary.all_pivot_tables().into_iter().map_into());
output.extend(cases_to_output(&dictionary, cases));
- driver
- .borrow_mut()
- .write(&Arc::new(Item::new(Details::Group(
- output.into_iter().map(Arc::new).collect(),
- ))));
+ driver.borrow_mut().write(&Arc::new(
+ output.into_iter().collect::<Details>().into_item(),
+ ));
}
Output::Json { .. } => {
output.show_json(&dictionary)?;
use anyhow::{Result, anyhow};
use clap::{Args, ValueEnum};
+use itertools::Itertools;
use pspp::{
data::cases_to_output,
output::{
match &output {
Output::Driver { driver, mode: _ } => {
let mut output = Vec::new();
- output.extend(
- dictionary
- .all_pivot_tables()
- .into_iter()
- .map(|pivot_table| Item::new(pivot_table)),
- );
+ output.extend(dictionary.all_pivot_tables().into_iter().map_into());
output.extend(cases_to_output(&dictionary, cases));
- driver
- .borrow_mut()
- .write(&Arc::new(Item::new(Details::Group(
- output.into_iter().map(Arc::new).collect(),
- ))));
+ driver.borrow_mut().write(&Arc::new(
+ output.into_iter().collect::<Details>().into_item(),
+ ));
}
Output::Json { .. } => {
output.show_json(&dictionary)?;
Output::Driver { driver, mode: _ } => {
driver
.borrow_mut()
- .write(&Arc::new(Item::new(PivotTable::from(&metadata))));
+ .write(&Arc::new(PivotTable::from(&metadata).into()));
}
Output::Json { .. } => {
output.show_json(&metadata)?;
use anyhow::{Result, anyhow};
use clap::{Args, ValueEnum};
+use itertools::Itertools;
use pspp::{
data::cases_to_output,
output::{
match &output {
Output::Driver { driver, mode: _ } => {
let mut output = Vec::new();
- output.extend(
- dictionary
- .all_pivot_tables()
- .into_iter()
- .map(|pivot_table| Item::new(pivot_table)),
- );
+ output.extend(dictionary.all_pivot_tables().into_iter().map_into());
output.extend(cases_to_output(&dictionary, cases));
- driver
- .borrow_mut()
- .write(&Arc::new(Item::new(Details::Group(
- output.into_iter().map(Arc::new).collect(),
- ))));
+ driver.borrow_mut().write(&Arc::new(
+ output.into_iter().collect::<Details>().into_item(),
+ ));
}
Output::Json { .. } => {
output.show_json(&dictionary)?;
Output::Driver { driver, mode: _ } => {
driver
.borrow_mut()
- .write(&Arc::new(Item::new(PivotTable::from(&metadata))));
+ .write(&Arc::new(PivotTable::from(&metadata).into()));
}
Output::Json { .. } => {
output.show_json(&metadata)?;
fs::File,
io::{BufRead, BufReader, Cursor, Seek},
path::{Path, PathBuf},
- sync::Arc,
};
use binrw::Endian;
}
output.push(pt.into());
}
- Item::new(Details::Group(output.into_iter().map(Arc::new).collect()))
+ output.into_iter().collect::<Details>().into_item()
}
- Err(error) => Item::new(Details::Text(Box::new(Text::new_log(error.to_string())))),
+ Err(error) => Details::Text(Box::new(Text::new_log(error.to_string()))).into_item(),
};
let actual = output.to_string();