use std::collections::HashSet; use super::util::assert_bounds; use super::util::assert_name; use super::util::get_property; use crate::parser::sexp::unquote; use crate::parser::sexp::Token; use crate::types::AngleLink; use crate::types::Bold; use crate::types::Citation; use crate::types::CitationReference; use crate::types::Clock; use crate::types::Code; use crate::types::Comment; use crate::types::CommentBlock; use crate::types::DiarySexp; use crate::types::Document; use crate::types::DocumentElement; use crate::types::Drawer; use crate::types::DynamicBlock; use crate::types::Element; use crate::types::Entity; use crate::types::ExampleBlock; use crate::types::ExportBlock; use crate::types::ExportSnippet; use crate::types::FixedWidthArea; use crate::types::FootnoteDefinition; use crate::types::FootnoteReference; use crate::types::GreaterBlock; use crate::types::Heading; use crate::types::HorizontalRule; use crate::types::InlineBabelCall; use crate::types::InlineSourceBlock; use crate::types::Italic; use crate::types::Keyword; use crate::types::LatexEnvironment; use crate::types::LatexFragment; use crate::types::LineBreak; use crate::types::Object; use crate::types::OrgMacro; use crate::types::Paragraph; use crate::types::PlainLink; use crate::types::PlainList; use crate::types::PlainListItem; use crate::types::PlainText; use crate::types::Planning; use crate::types::PropertyDrawer; use crate::types::RadioLink; use crate::types::RadioTarget; use crate::types::RegularLink; use crate::types::Section; use crate::types::Source; use crate::types::SrcBlock; use crate::types::StatisticsCookie; use crate::types::StrikeThrough; use crate::types::Subscript; use crate::types::Superscript; use crate::types::Table; use crate::types::TableCell; use crate::types::TableRow; use crate::types::Target; use crate::types::Timestamp; use crate::types::TodoKeywordType; use crate::types::Underline; use crate::types::Verbatim; use crate::types::VerseBlock; #[derive(Debug)] pub enum DiffEntry<'s> { DiffResult(DiffResult<'s>), DiffLayer(DiffLayer<'s>), } #[derive(Debug)] pub struct DiffResult<'s> { status: DiffStatus, name: String, message: Option, children: Vec>, rust_source: &'s str, #[allow(dead_code)] emacs_token: &'s Token<'s>, } #[derive(Debug, PartialEq)] pub enum DiffStatus { Good, Bad, } #[derive(Debug)] pub struct DiffLayer<'s> { name: String, children: Vec>, } impl<'s> From> for DiffEntry<'s> { fn from(value: DiffResult<'s>) -> Self { DiffEntry::DiffResult(value) } } impl<'s> From> for DiffEntry<'s> { fn from(value: DiffLayer<'s>) -> Self { DiffEntry::DiffLayer(value) } } impl<'s> DiffEntry<'s> { fn has_bad_children(&self) -> bool { match self { DiffEntry::DiffResult(diff) => &diff.children, DiffEntry::DiffLayer(diff) => &diff.children, } .iter() .any(|child| child.is_immediately_bad() || child.has_bad_children()) } fn is_immediately_bad(&self) -> bool { match self { DiffEntry::DiffResult(diff) => diff.status == DiffStatus::Bad, DiffEntry::DiffLayer(_) => false, } } pub fn is_bad(&self) -> bool { self.is_immediately_bad() || self.has_bad_children() } pub fn print(&self, original_document: &str) -> Result<(), Box> { self.print_indented(0, original_document) } fn print_indented( &self, indentation: usize, original_document: &str, ) -> Result<(), Box> { match self { DiffEntry::DiffResult(diff) => diff.print_indented(indentation, original_document), DiffEntry::DiffLayer(diff) => diff.print_indented(indentation, original_document), } } } impl<'s> DiffResult<'s> { fn print_indented( &self, indentation: usize, original_document: &str, ) -> Result<(), Box> { let status_text = { match self.status { DiffStatus::Good => { if self.has_bad_children() { format!( "{color}BADCHILD{reset}", color = DiffResult::foreground_color(255, 255, 0), reset = DiffResult::reset_color(), ) } else { format!( "{color}GOOD{reset}", color = DiffResult::foreground_color(0, 255, 0), reset = DiffResult::reset_color(), ) } } DiffStatus::Bad => format!( "{color}BAD{reset}", color = DiffResult::foreground_color(255, 0, 0), reset = DiffResult::reset_color(), ), } }; let rust_offset = self.rust_source.as_ptr() as usize - original_document.as_ptr() as usize; let preceding_text = &original_document[..rust_offset]; println!( "{indentation}{status_text} {name} char({char_offset}) {message}", indentation = " ".repeat(indentation), status_text = status_text, name = self.name, char_offset = preceding_text.chars().count() + 1, message = self.message.as_ref().map(|m| m.as_str()).unwrap_or("") ); for child in self.children.iter() { child.print_indented(indentation + 1, original_document)?; } Ok(()) } fn has_bad_children(&self) -> bool { self.children .iter() .any(|child| child.is_immediately_bad() || child.has_bad_children()) } fn foreground_color(red: u8, green: u8, blue: u8) -> String { if DiffResult::should_use_color() { format!( "\x1b[38;2;{red};{green};{blue}m", red = red, green = green, blue = blue ) } else { String::new() } } #[allow(dead_code)] fn background_color(red: u8, green: u8, blue: u8) -> String { if DiffResult::should_use_color() { format!( "\x1b[48;2;{red};{green};{blue}m", red = red, green = green, blue = blue ) } else { String::new() } } fn reset_color() -> &'static str { if DiffResult::should_use_color() { "\x1b[0m" } else { "" } } fn should_use_color() -> bool { !std::env::var("NO_COLOR").is_ok_and(|val| !val.is_empty()) } } impl<'s> DiffLayer<'s> { fn has_bad_children(&self) -> bool { self.children .iter() .any(|child| child.is_immediately_bad() || child.has_bad_children()) } fn print_indented( &self, indentation: usize, original_document: &str, ) -> Result<(), Box> { let status_text = if self.has_bad_children() { format!( "{color}BADCHILD{reset}", color = DiffResult::foreground_color(255, 255, 0), reset = DiffResult::reset_color(), ) } else { format!( "{color}GOOD{reset}", color = DiffResult::foreground_color(0, 255, 0), reset = DiffResult::reset_color(), ) }; println!( "{indentation}{status_text} {name}", indentation = " ".repeat(indentation), status_text = status_text, name = self.name, ); for child in self.children.iter() { child.print_indented(indentation + 1, original_document)?; } Ok(()) } } fn artificial_diff_scope<'s>( name: String, children: Vec>, ) -> Result, Box> { Ok(DiffLayer { name, children }.into()) } fn compare_element<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Element<'s>, ) -> Result, Box> { let compare_result = match rust { Element::Paragraph(obj) => compare_paragraph(source, emacs, obj), Element::PlainList(obj) => compare_plain_list(source, emacs, obj), Element::GreaterBlock(obj) => compare_greater_block(source, emacs, obj), Element::DynamicBlock(obj) => compare_dynamic_block(source, emacs, obj), Element::FootnoteDefinition(obj) => compare_footnote_definition(source, emacs, obj), Element::Comment(obj) => compare_comment(source, emacs, obj), Element::Drawer(obj) => compare_drawer(source, emacs, obj), Element::PropertyDrawer(obj) => compare_property_drawer(source, emacs, obj), Element::Table(obj) => compare_table(source, emacs, obj), Element::VerseBlock(obj) => compare_verse_block(source, emacs, obj), Element::CommentBlock(obj) => compare_comment_block(source, emacs, obj), Element::ExampleBlock(obj) => compare_example_block(source, emacs, obj), Element::ExportBlock(obj) => compare_export_block(source, emacs, obj), Element::SrcBlock(obj) => compare_src_block(source, emacs, obj), Element::Clock(obj) => compare_clock(source, emacs, obj), Element::DiarySexp(obj) => compare_diary_sexp(source, emacs, obj), Element::Planning(obj) => compare_planning(source, emacs, obj), Element::FixedWidthArea(obj) => compare_fixed_width_area(source, emacs, obj), Element::HorizontalRule(obj) => compare_horizontal_rule(source, emacs, obj), Element::Keyword(obj) => compare_keyword(source, emacs, obj), Element::BabelCall(obj) => compare_babel_call(source, emacs, obj), Element::LatexEnvironment(obj) => compare_latex_environment(source, emacs, obj), }; match compare_result { Ok(_) => compare_result, Err(ref e) => Ok(DiffResult { status: DiffStatus::Bad, name: "error!".to_owned(), message: Some(e.to_string()), children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()), } } fn compare_object<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Object<'s>, ) -> Result, Box> { let compare_result = match rust { Object::Bold(obj) => compare_bold(source, emacs, obj), Object::Italic(obj) => compare_italic(source, emacs, obj), Object::Underline(obj) => compare_underline(source, emacs, obj), Object::Verbatim(obj) => compare_verbatim(source, emacs, obj), Object::Code(obj) => compare_code(source, emacs, obj), Object::StrikeThrough(obj) => compare_strike_through(source, emacs, obj), Object::PlainText(obj) => compare_plain_text(source, emacs, obj), Object::RegularLink(obj) => compare_regular_link(source, emacs, obj), Object::RadioLink(obj) => compare_radio_link(source, emacs, obj), Object::RadioTarget(obj) => compare_radio_target(source, emacs, obj), Object::PlainLink(obj) => compare_plain_link(source, emacs, obj), Object::AngleLink(obj) => compare_angle_link(source, emacs, obj), Object::OrgMacro(obj) => compare_org_macro(source, emacs, obj), Object::Entity(obj) => compare_entity(source, emacs, obj), Object::LatexFragment(obj) => compare_latex_fragment(source, emacs, obj), Object::ExportSnippet(obj) => compare_export_snippet(source, emacs, obj), Object::FootnoteReference(obj) => compare_footnote_reference(source, emacs, obj), Object::Citation(obj) => compare_citation(source, emacs, obj), Object::CitationReference(obj) => compare_citation_reference(source, emacs, obj), Object::InlineBabelCall(obj) => compare_inline_babel_call(source, emacs, obj), Object::InlineSourceBlock(obj) => compare_inline_source_block(source, emacs, obj), Object::LineBreak(obj) => compare_line_break(source, emacs, obj), Object::Target(obj) => compare_target(source, emacs, obj), Object::StatisticsCookie(obj) => compare_statistics_cookie(source, emacs, obj), Object::Subscript(obj) => compare_subscript(source, emacs, obj), Object::Superscript(obj) => compare_superscript(source, emacs, obj), Object::Timestamp(obj) => compare_timestamp(source, emacs, obj), }; match compare_result { Ok(_) => compare_result, Err(ref e) => Ok(DiffResult { status: DiffStatus::Bad, name: "error!".to_owned(), message: Some(e.to_string()), children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()), } } pub fn compare_document<'s>( emacs: &'s Token<'s>, rust: &'s Document<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; let emacs_name = "org-data"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } // Skipping "org-data" and the first parameter which is often nil for (i, token) in children.iter().skip(2).enumerate() { let section_or_headline = token.as_list()?; let first_cell = section_or_headline .first() .ok_or("Should have at least one child.")? .as_atom()?; if first_cell == "section" { if i != 0 { return Err("Section cannot be after the first child of document.".into()); } child_status.push(compare_section( rust.source, token, rust.zeroth_section .as_ref() .ok_or("No corresponding zeroth-section")?, )?); } else if first_cell == "headline" { let corresponding_heading = rust .children .iter() .nth(i - rust.zeroth_section.as_ref().map(|_| 1).unwrap_or(0)) .ok_or("Should have a corresponding heading.")?; child_status.push(compare_heading(rust.source, token, corresponding_heading)?); } else { return Err("Document should only contain sections and headlines.".into()); } } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message: None, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_section<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Section<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut this_status = DiffStatus::Good; let mut child_status = Vec::new(); let mut message = None; let emacs_name = "section"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_element(source, emacs_child, rust_child)?); } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_heading<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Heading<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "headline"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; // Compare level let level = get_property(emacs, ":level")? .ok_or("Level should not be nil")? .as_atom()?; if rust.stars.to_string() != level { this_status = DiffStatus::Bad; message = Some(format!( "Headline level do not much (emacs != rust): {} != {}", level, rust.stars )) } // Compare tags let emacs_tags = get_tags_from_heading(emacs)?; let emacs_tags: HashSet<_> = emacs_tags.iter().map(|val| val.as_str()).collect(); let rust_tags: HashSet<&str> = rust.tags.iter().map(|val| *val).collect(); let difference: Vec<&str> = emacs_tags .symmetric_difference(&rust_tags) .map(|val| *val) .collect(); if !difference.is_empty() { this_status = DiffStatus::Bad; message = Some(format!("Mismatched tags: {}", difference.join(", "))); } // Compare todo-keyword let todo_keyword = get_property(emacs, ":todo-keyword")? .map(Token::as_atom) .map_or(Ok(None), |r| r.map(Some))? .unwrap_or("nil"); match (todo_keyword, &rust.todo_keyword, unquote(todo_keyword)) { ("nil", None, _) => {} (_, Some((_rust_todo_type, rust_todo)), Ok(emacs_todo)) if emacs_todo == *rust_todo => {} (emacs_todo, rust_todo, _) => { this_status = DiffStatus::Bad; message = Some(format!( "(emacs != rust) {:?} != {:?}", emacs_todo, rust_todo )); } }; // Compare todo-type let todo_type = get_property(emacs, ":todo-type")? .map(Token::as_atom) .map_or(Ok(None), |r| r.map(Some))? .unwrap_or("nil"); // todo-type is an unquoted string either todo, done, or nil match (todo_type, &rust.todo_keyword) { ("nil", None) => {} ("todo", Some((TodoKeywordType::Todo, _))) => {} ("done", Some((TodoKeywordType::Done, _))) => {} (emacs_todo, rust_todo) => { this_status = DiffStatus::Bad; message = Some(format!( "(emacs != rust) {:?} != {:?}", emacs_todo, rust_todo )); } }; // Compare title let title = get_property(emacs, ":title")?.ok_or("Missing :title attribute.")?; let title_status = title .as_list()? .iter() .zip(rust.title.iter()) .map(|(emacs_child, rust_child)| compare_object(source, emacs_child, rust_child)) .collect::, _>>()?; child_status.push(artificial_diff_scope("title".to_owned(), title_status)?); // TODO: Compare priority, :footnote-section-p, :archivedp, :commentedp // Compare section let section_status = children .iter() .skip(2) .zip(rust.children.iter()) .map(|(emacs_child, rust_child)| match rust_child { DocumentElement::Heading(rust_heading) => { compare_heading(source, emacs_child, rust_heading) } DocumentElement::Section(rust_section) => { compare_section(source, emacs_child, rust_section) } }) .collect::, _>>()?; child_status.push(artificial_diff_scope("section".to_owned(), section_status)?); Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn get_tags_from_heading<'s>( emacs: &'s Token<'s>, ) -> Result, Box> { let tags = match get_property(emacs, ":tags")? { Some(prop) => prop, None => return Ok(HashSet::new()), }; match tags.as_atom() { Ok(val) => panic!("Unexpected value for tags: {:?}", val), Err(_) => {} }; let tags = { let tags = tags.as_list()?; let strings = tags .iter() .map(Token::as_atom) .collect::, _>>()?; strings .into_iter() .map(unquote) .collect::, _>>()? }; Ok(tags) } fn compare_paragraph<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Paragraph<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "paragraph"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_object(source, emacs_child, rust_child)?); } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_plain_list<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s PlainList<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "plain-list"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_plain_list_item(source, emacs_child, rust_child)?); } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_plain_list_item<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s PlainListItem<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "item"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; // Compare tag let tag = get_property(emacs, ":tag")?; match (tag, rust.tag.is_empty()) { (None, true) => {} (None, false) | (Some(_), true) => { this_status = DiffStatus::Bad; message = Some("Mismatched tags".to_owned()); } (Some(tag), false) => { let tag_status = tag .as_list()? .iter() .zip(rust.tag.iter()) .map(|(emacs_child, rust_child)| compare_object(source, emacs_child, rust_child)) .collect::, _>>()?; child_status.push(artificial_diff_scope("tag".to_owned(), tag_status)?); } }; // Compare contents let contents_status = children .iter() .skip(2) .zip(rust.children.iter()) .map(|(emacs_child, rust_child)| compare_element(source, emacs_child, rust_child)) .collect::, _>>()?; child_status.push(artificial_diff_scope( "contents".to_owned(), contents_status, )?); Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_greater_block<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s GreaterBlock<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = match rust.name.to_lowercase().as_str() { "center" => "center-block", "quote" => "quote-block", _ => "special-block", }; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_element(source, emacs_child, rust_child)?); } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_dynamic_block<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s DynamicBlock<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; if assert_name(emacs, "dynamic-block").is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_element(source, emacs_child, rust_child)?); } Ok(DiffResult { status: this_status, name: "dynamic-block".to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_footnote_definition<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s FootnoteDefinition<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "footnote-definition"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_element(source, emacs_child, rust_child)?); } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_comment<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Comment<'s>, ) -> Result, Box> { let child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "comment"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_drawer<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Drawer<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "drawer"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_element(source, emacs_child, rust_child)?); } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_property_drawer<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s PropertyDrawer<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "property-drawer"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (_emacs_child, _rust_child) in children.iter().skip(2).zip(rust.children.iter()) { // TODO: What are node properties and are they the only legal child of property drawers? // child_status.push(compare_element(source, emacs_child, rust_child)?); } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_table<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Table<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "table"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_table_row(source, emacs_child, rust_child)?); } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_table_row<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s TableRow<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "table-row"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_table_cell(source, emacs_child, rust_child)?); } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_table_cell<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s TableCell<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "table-cell"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (_emacs_child, _rust_child) in children.iter().skip(2).zip(rust.children.iter()) {} Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_verse_block<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s VerseBlock<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "verse-block"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; for (_emacs_child, _rust_child) in children.iter().skip(2).zip(rust.children.iter()) {} Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_comment_block<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s CommentBlock<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "comment-block"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_example_block<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s ExampleBlock<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "example-block"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_export_block<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s ExportBlock<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "export-block"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_src_block<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s SrcBlock<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "src-block"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; // TODO: Compare :language :switches :parameters :number-lines :preserve-indent :retain-labels :use-labels :label-fmt :value Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_clock<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Clock<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "clock"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_diary_sexp<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s DiarySexp<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "diary-sexp"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_planning<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Planning<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "planning"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_fixed_width_area<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s FixedWidthArea<'s>, ) -> Result, Box> { let child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "fixed-width"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_horizontal_rule<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s HorizontalRule<'s>, ) -> Result, Box> { let child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "horizontal-rule"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_keyword<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Keyword<'s>, ) -> Result, Box> { let child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "keyword"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; let key = unquote( get_property(emacs, ":key")? .ok_or("Emacs keywords should have a :key")? .as_atom()?, )?; if key != rust.key.to_uppercase() { this_status = DiffStatus::Bad; message = Some(format!( "Mismatchs keyword keys (emacs != rust) {:?} != {:?}", key, rust.key )) } let value = unquote( get_property(emacs, ":value")? .ok_or("Emacs keywords should have a :value")? .as_atom()?, )?; if value != rust.value { this_status = DiffStatus::Bad; message = Some(format!( "Mismatchs keyword values (emacs != rust) {:?} != {:?}", value, rust.value )) } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_babel_call<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Keyword<'s>, ) -> Result, Box> { let child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "babel-call"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; // TODO: compare :call :inside-header :arguments :end-header let value = unquote( get_property(emacs, ":value")? .ok_or("Emacs keywords should have a :value")? .as_atom()?, )?; if value != rust.value { this_status = DiffStatus::Bad; message = Some(format!( "Mismatchs keyword values (emacs != rust) {:?} != {:?}", value, rust.value )) } Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_latex_environment<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s LatexEnvironment<'s>, ) -> Result, Box> { let child_status = Vec::new(); let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "latex-environment"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: child_status, rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_plain_text<'s>( _source: &'s str, emacs: &'s Token<'s>, rust: &'s PlainText<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let rust_source = rust.get_source(); let text = emacs.as_text()?; let start_ind: usize = text .properties .get(0) .expect("Should have start index.") .as_atom()? .parse()?; let end_ind: usize = text .properties .get(1) .expect("Should have end index.") .as_atom()? .parse()?; let emacs_text_length = end_ind - start_ind; if rust_source.chars().count() != emacs_text_length { this_status = DiffStatus::Bad; message = Some(format!( "(emacs len != rust len) {:?} != {:?}", emacs_text_length, rust_source.len() )); } let unquoted_text = unquote(text.text)?; if unquoted_text != rust_source { this_status = DiffStatus::Bad; message = Some(format!( "(emacs != rust) {:?} != {:?}", unquoted_text, rust_source )); } Ok(DiffResult { status: this_status, name: "plain-text".to_owned(), message, children: Vec::new(), rust_source, emacs_token: emacs, } .into()) } fn compare_bold<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Bold<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "bold"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_italic<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Italic<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "italic"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_underline<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Underline<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "underline"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_verbatim<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Verbatim<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "verbatim"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_code<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Code<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "code"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_strike_through<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s StrikeThrough<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "strike-through"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_regular_link<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s RegularLink<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "link"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_radio_link<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s RadioLink<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "link"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_radio_target<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s RadioTarget<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "radio-target"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_plain_link<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s PlainLink<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "link"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_angle_link<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s AngleLink<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "link"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_org_macro<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s OrgMacro<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "macro"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_entity<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Entity<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "entity"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_latex_fragment<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s LatexFragment<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "latex-fragment"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_export_snippet<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s ExportSnippet<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "export-snippet"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_footnote_reference<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s FootnoteReference<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "footnote-reference"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_citation<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Citation<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "citation"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_citation_reference<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s CitationReference<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "citation-reference"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_inline_babel_call<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s InlineBabelCall<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "inline-babel-call"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_inline_source_block<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s InlineSourceBlock<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "inline-src-block"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_line_break<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s LineBreak<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "line-break"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_target<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Target<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "target"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_statistics_cookie<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s StatisticsCookie<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "statistics-cookie"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_subscript<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Subscript<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "subscript"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_superscript<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Superscript<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "superscript"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) } fn compare_timestamp<'s>( source: &'s str, emacs: &'s Token<'s>, rust: &'s Timestamp<'s>, ) -> Result, Box> { let mut this_status = DiffStatus::Good; let mut message = None; let emacs_name = "timestamp"; if assert_name(emacs, emacs_name).is_err() { this_status = DiffStatus::Bad; } match assert_bounds(source, emacs, rust) { Err(err) => { this_status = DiffStatus::Bad; message = Some(err.to_string()) } Ok(_) => {} }; Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), message, children: Vec::new(), rust_source: rust.get_source(), emacs_token: emacs, } .into()) }