tamer: ir::xir::tree::Element::attrs: Wrap in Option
This allows AttrList not only to be lazily initialized (which is less of a problem at the moment with Vec, but may become one in the future), but also leaves a space open for attributes to be added _after_ having been parsed. It further leaves room to _take_ attributes from their `Element`. This is important because the next commit will re-introduce the ability to parse attributes independently, allowing us to put the parser in a state where we can parse AttrList without an Element context. To re-use that parsing under an Element context, we can simply attach an AttrList after it has been parsed. Option adds no additional size cost to Vec, so we get this for free (except for the tiny change that initializes the attribute list when we try to push to it). I also think this reads better ("attrs: None"). Though it makes the API slightly more of a pain to work with. DEV-10863main
parent
a9fd1c7557
commit
d045786cfb
|
@ -307,7 +307,7 @@ impl Tree {
|
|||
pub struct Element {
|
||||
name: QName,
|
||||
/// Zero or more attributes.
|
||||
attrs: AttrList,
|
||||
attrs: Option<AttrList>,
|
||||
/// Zero or more child nodes.
|
||||
children: Vec<Tree>,
|
||||
/// Spans for opening and closing tags respectively.
|
||||
|
@ -329,8 +329,8 @@ impl Element {
|
|||
|
||||
/// Attributes of this element.
|
||||
#[inline]
|
||||
pub fn attrs(&self) -> &AttrList {
|
||||
&self.attrs
|
||||
pub fn attrs(&self) -> Option<&AttrList> {
|
||||
self.attrs.as_ref()
|
||||
}
|
||||
|
||||
/// Opens an element for incremental construction.
|
||||
|
@ -343,7 +343,7 @@ impl Element {
|
|||
fn open(name: QName, span: Span) -> Self {
|
||||
Self {
|
||||
name,
|
||||
attrs: AttrList::new(),
|
||||
attrs: None,
|
||||
children: vec![],
|
||||
span: (span, span), // We do not yet know where the span will end
|
||||
}
|
||||
|
@ -450,7 +450,7 @@ impl ElementStack {
|
|||
/// Push the provided [`Attr`] onto the attribute list of the inner
|
||||
/// [`Element`].
|
||||
fn consume_attr(mut self, attr: Attr) -> Self {
|
||||
self.element.attrs.push(attr);
|
||||
self.element.attrs.get_or_insert_default().push(attr);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ mod tree {
|
|||
fn element_from_tree() {
|
||||
let ele = Element {
|
||||
name: "foo".unwrap_into(),
|
||||
attrs: AttrList::new(),
|
||||
attrs: None,
|
||||
children: vec![],
|
||||
span: (*S, *S2),
|
||||
};
|
||||
|
@ -94,7 +94,7 @@ fn empty_element_self_close_from_toks() {
|
|||
|
||||
let expected = Element {
|
||||
name,
|
||||
attrs: AttrList::new(),
|
||||
attrs: None,
|
||||
children: vec![],
|
||||
span: (*S, *S2),
|
||||
};
|
||||
|
@ -120,7 +120,7 @@ fn empty_element_balanced_close_from_toks() {
|
|||
|
||||
let expected = Element {
|
||||
name,
|
||||
attrs: AttrList::new(),
|
||||
attrs: None,
|
||||
children: vec![],
|
||||
span: (*S, *S2),
|
||||
};
|
||||
|
@ -188,14 +188,14 @@ fn empty_element_with_attrs_from_toks() {
|
|||
|
||||
let expected = Element {
|
||||
name,
|
||||
attrs: AttrList::from(vec![
|
||||
attrs: Some(AttrList::from(vec![
|
||||
Attr::new(attr1, val1, (*S, *S2)),
|
||||
Attr::from_fragments(
|
||||
attr2,
|
||||
*S,
|
||||
vec![(val2a, *S), (val2b, *S2), (val2c, *S3)],
|
||||
),
|
||||
]),
|
||||
])),
|
||||
children: vec![],
|
||||
span: (*S, *S2),
|
||||
};
|
||||
|
@ -234,17 +234,17 @@ fn element_with_empty_sibling_children() {
|
|||
|
||||
let expected = Element {
|
||||
name: parent,
|
||||
attrs: AttrList::new(),
|
||||
attrs: None,
|
||||
children: vec![
|
||||
Tree::Element(Element {
|
||||
name: childa,
|
||||
attrs: AttrList::new(),
|
||||
attrs: None,
|
||||
children: vec![],
|
||||
span: (*S, *S2),
|
||||
}),
|
||||
Tree::Element(Element {
|
||||
name: childb,
|
||||
attrs: AttrList::new(),
|
||||
attrs: None,
|
||||
children: vec![],
|
||||
span: (*S, *S2),
|
||||
}),
|
||||
|
@ -278,10 +278,10 @@ fn element_with_child_with_attributes() {
|
|||
|
||||
let expected = Element {
|
||||
name: parent,
|
||||
attrs: AttrList::new(),
|
||||
attrs: None,
|
||||
children: vec![Tree::Element(Element {
|
||||
name: child,
|
||||
attrs: AttrList::from([Attr::new(attr, value, (*S, *S2))]),
|
||||
attrs: Some(AttrList::from([Attr::new(attr, value, (*S, *S2))])),
|
||||
children: vec![],
|
||||
span: (*S, *S3),
|
||||
})],
|
||||
|
@ -308,7 +308,7 @@ fn element_with_text() {
|
|||
|
||||
let expected = Element {
|
||||
name: parent,
|
||||
attrs: AttrList::new(),
|
||||
attrs: None,
|
||||
children: vec![Tree::Text(text, *S2)],
|
||||
span: (*S, *S3),
|
||||
};
|
||||
|
@ -335,7 +335,7 @@ fn parser_from_filters_incomplete() {
|
|||
|
||||
let expected = Element {
|
||||
name,
|
||||
attrs: AttrList::from([Attr::new(attr, val, (*S, *S2))]),
|
||||
attrs: Some(AttrList::from([Attr::new(attr, val, (*S, *S2))])),
|
||||
children: vec![],
|
||||
span: (*S, *S2),
|
||||
};
|
||||
|
|
|
@ -252,7 +252,7 @@ fn test_writes_deps() -> TestResult {
|
|||
|
||||
p_syms.enumerate().for_each(|(i, ele)| {
|
||||
let ident = &objs[i];
|
||||
let attrs = ele.attrs();
|
||||
let attrs = ele.attrs().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
attrs.find(QN_NAME).and_then(|a| a.value_atom()),
|
||||
|
@ -435,6 +435,7 @@ fn test_writes_map_froms() -> TestResult {
|
|||
from.as_element()
|
||||
.unwrap()
|
||||
.attrs()
|
||||
.unwrap()
|
||||
.find(QN_NAME)
|
||||
.expect("expecting @name")
|
||||
.value_atom()
|
||||
|
|
|
@ -36,6 +36,11 @@
|
|||
// Can be replaced with `assert!(matches!(...))`,
|
||||
// but at a loss of a better error message.
|
||||
#![feature(assert_matches)]
|
||||
// Simplifies creating `Option` default values.
|
||||
// To remove this feature,
|
||||
// this can be done more verbosely in the usual way,
|
||||
// or we can write our own version.
|
||||
#![feature(option_get_or_insert_default)]
|
||||
// We build docs for private items.
|
||||
#![allow(rustdoc::private_intra_doc_links)]
|
||||
|
||||
|
|
Loading…
Reference in New Issue