-
Notifications
You must be signed in to change notification settings - Fork 0
feat!: Implement Display, PartialEq<...Buf> and FromStr for basic name types
#150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request implements the Display trait for all *Buf (owned) name types and adds cross-type PartialEq implementations to allow direct comparison between borrowed and owned variants. Additionally, it updates the Display implementation for ExpandedName to include the namespace when present, and adds constructor methods for XmlNamespaceBuf.
Key changes:
- Updated
ExpandedName::Displayto format namespace and local name together when namespace is present - Added
Displayimplementations for all*Buftypes (delegating to their borrowed counterparts) - Added symmetric
PartialEqimplementations between borrowed and owned types forQName,XmlNamespace,Prefix, andLocalName - Added
newandnew_uncheckedconstructor methods forXmlNamespaceBuf
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
xmlity/src/lib.rs
Outdated
| if let Some(namespace) = &self.namespace { | ||
| write!(f, "{}:{}", namespace, self.local_name) |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test at line 849 expects expanded_name.to_string() to equal just local_name_text even when a namespace is present (see case at line 843). With the updated Display implementation that includes the namespace, this test will fail for the with_namespace case. The test assertion needs to be updated to match the expected Display format, which should account for whether a namespace is present or not.
xmlity/src/lib.rs
Outdated
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| self.local_name.fmt(f) | ||
| if let Some(namespace) = &self.namespace { | ||
| write!(f, "{}:{}", namespace, self.local_name) |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a colon separator between namespace and local name is problematic because it conflicts with the syntax for qualified names (QName), where the colon separates a prefix from a local name. An ExpandedName represents a namespace URI (not a prefix) combined with a local name. Consider using Clark notation format instead, which uses braces: {namespace}localName. This is a well-established convention for representing expanded names in XML processing.
| write!(f, "{}:{}", namespace, self.local_name) | |
| write!(f, "{{{}}}{}", namespace, self.local_name) |
Display and PartialEq<...Buf> for basic name typesDisplay, PartialEq<...Buf> and FromStr for basic name types
Display, PartialEq<...Buf> and FromStr for basic name typesDisplay, PartialEq<...Buf> and FromStr for basic name types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| impl Display for ExpandedNameBuf { | ||
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| self.as_ref().fmt(f) | ||
| } | ||
| } |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR adds PartialEq cross-implementations between borrowed and owned versions for all other name types (QName/QNameBuf, XmlNamespace/XmlNamespaceBuf, Prefix/PrefixBuf, LocalName/LocalNameBuf), but these implementations are missing for ExpandedName and ExpandedNameBuf. For consistency, consider adding impl PartialEq<ExpandedName<'_>> for ExpandedNameBuf and impl PartialEq<ExpandedNameBuf> for ExpandedName<'_> following the same pattern as the other types.
| impl FromStr for ExpandedNameBuf { | ||
| type Err = ExpandedNameParseError; | ||
| fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
| let s = s.trim(); |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of trim() here is inconsistent with other FromStr implementations in this file (e.g., QNameBuf::from_str at line 324, LocalNameBuf::from_str at line 789, PrefixBuf::from_str at line 624), which do not trim whitespace. This could lead to unexpected behavior where whitespace is silently removed. Consider removing the trim call for consistency, or if trimming is intentional, apply it consistently across all name type parsers.
| let s = s.trim(); |
xmlity/src/lib.rs
Outdated
| } | ||
| } | ||
|
|
||
| /// An error that can occur when parsing a [`QName`]. |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation comment incorrectly states this is "An error that can occur when parsing a [QName]", but this enum is actually ExpandedNameParseError and should reference ExpandedName or ExpandedNameBuf instead.
| /// An error that can occur when parsing a [`QName`]. | |
| /// An error that can occur when parsing an [`ExpandedNameBuf`]. |
| impl FromStr for ExpandedNameBuf { | ||
| type Err = ExpandedNameParseError; | ||
| fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
| let s = s.trim(); | ||
| if !s.starts_with('{') { | ||
| let local_name = s.parse()?; | ||
|
|
||
| return Ok(ExpandedNameBuf::new(local_name, None)); | ||
| } | ||
|
|
||
| let closing_brace_index = s | ||
| .find('}') | ||
| .ok_or(ExpandedNameParseError::MissingClosingBrace)?; | ||
| let namespace = s[1..closing_brace_index].parse()?; | ||
| let local_name = s[(closing_brace_index + 1)..].parse()?; | ||
| Ok(ExpandedNameBuf::new(local_name, Some(namespace))) | ||
| } | ||
| } |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The FromStr implementation for ExpandedNameBuf lacks test coverage. Other similar types in the file (e.g., QNameBuf at line 893, LocalNameBuf at line 859) have corresponding tests for their FromStr implementations. Consider adding test cases that verify parsing of expanded names with and without namespaces, as well as error cases like missing closing braces or invalid local names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
xmlity/src/lib.rs:345
- After trimming the input at line 337, the prefix and local_name parts extracted from splitting at line 338 will be passed to their respective FromStr implementations (lines 343, 345), which will trim them again (lines 638, 803). This means that a QName like "prefix : localName" (with spaces around the colon) will be accepted and parsed as "prefix:localName", which may not be the intended behavior since XML QNames should not have whitespace around the colon separator. Consider whether the trimming should only happen at the top level or if the individual parts should be trimmed.
let s = s.trim();
let (prefix, local_name) = s.split_once(':').unwrap_or(("", s));
let prefix = if prefix.is_empty() {
None
} else {
Some(PrefixBuf::from_str(prefix)?)
};
let local_name = LocalNameBuf::from_str(local_name)?;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let s = s.trim(); | ||
| if !s.starts_with('{') { | ||
| let local_name = s.parse()?; | ||
|
|
||
| return Ok(ExpandedNameBuf::new(local_name, None)); | ||
| } | ||
|
|
||
| let closing_brace_index = s | ||
| .find('}') | ||
| .ok_or(ExpandedNameParseError::MissingClosingBrace)?; | ||
| let namespace = s[1..closing_brace_index].parse()?; | ||
| let local_name = s[(closing_brace_index + 1)..].parse()?; | ||
| Ok(ExpandedNameBuf::new(local_name, Some(namespace))) |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the QNameBuf parser, the trimming at line 219 combined with the recursive trimming in the LocalNameBuf and XmlNamespaceBuf parsers (lines 491, 803) could lead to accepting inputs with internal whitespace. For example, "{http://example.com} localName" (with a space after the closing brace) would be parsed successfully, which may not be the intended behavior for expanded names. Consider whether trimming should only occur at the top level or if the format should be strictly validated.
| #[error("Missing closing brace in expanded name")] | ||
| MissingClosingBrace, |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new ExpandedNameParseError::MissingClosingBrace error case is not covered by tests. Consider adding a test case that verifies the error is correctly returned when parsing an expanded name like "{http://example.com" (missing closing brace).
| impl PartialEq<ExpandedName<'_>> for ExpandedNameBuf { | ||
| fn eq(&self, other: &ExpandedName<'_>) -> bool { | ||
| self.as_ref() == *other | ||
| } | ||
| } | ||
|
|
||
| impl PartialEq<ExpandedNameBuf> for ExpandedName<'_> { | ||
| fn eq(&self, other: &ExpandedNameBuf) -> bool { | ||
| *self == other.as_ref() | ||
| } | ||
| } |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new PartialEq implementations between owned (*Buf) and borrowed types (e.g., ExpandedNameBuf and ExpandedName, QNameBuf and QName, etc.) are not covered by tests. Consider adding tests that verify these cross-type comparisons work correctly.
| impl Display for ExpandedNameBuf { | ||
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| self.as_ref().fmt(f) | ||
| } | ||
| } |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new Display implementations for the owned types (ExpandedNameBuf, XmlNamespaceBuf, PrefixBuf, LocalNameBuf) are not directly tested. While the borrowed types' Display implementations are tested indirectly through to_string() calls, consider adding explicit tests for the owned types to ensure the delegation works correctly.
No description provided.