Skip to content
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

Make const as many functions as possible #759

Merged
merged 2 commits into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,37 @@
### Misc Changes

- [#650]: Change the type of `Event::PI` to a new dedicated `BytesPI` type.
- [#759]: Make `const` as much functions as possible:
- `resolve_html5_entity()`
- `resolve_predefined_entity()`
- `resolve_xml_entity()`
- `Attr::key()`
- `Attr::value()`
- `Attributes::html()`
- `Attributes::new()`
- `BytesDecl::from_start()`
- `Decoder::encoding()`
- `Deserializer::get_ref()`
- `IoReader::get_ref()`
- `LocalName::into_inner()`
- `Namespace::into_inner()`
- `NsReader::config()`
- `NsReader::prefixes()`
- `Prefix::into_inner()`
- `QName::into_inner()`
- `Reader::buffer_position()`
- `Reader::config()`
- `Reader::decoder()`
- `Reader::error_position()`
- `Reader::get_ref()`
- `SliceReader::get_ref()`
- `Writer::get_ref()`
- `Writer::new()`

[#650]: https://github.com/tafia/quick-xml/issues/650
[#755]: https://github.com/tafia/quick-xml/pull/755
[#758]: https://github.com/tafia/quick-xml/pull/758
[#759]: https://github.com/tafia/quick-xml/pull/759


## 0.32.0 -- 2024-06-10
Expand Down
10 changes: 5 additions & 5 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2155,7 +2155,7 @@ impl<'i, R: XmlRead<'i>, E: EntityResolver> XmlReader<'i, R, E> {
}

/// Returns `true` if all events was consumed
fn is_empty(&self) -> bool {
const fn is_empty(&self) -> bool {
matches!(self.lookahead, Ok(PayloadEvent::Eof))
}

Expand All @@ -2166,7 +2166,7 @@ impl<'i, R: XmlRead<'i>, E: EntityResolver> XmlReader<'i, R, E> {
}

#[inline(always)]
fn need_trim_end(&self) -> bool {
const fn need_trim_end(&self) -> bool {
// If next event is a text or CDATA, we should not trim trailing spaces
!matches!(
self.lookahead,
Expand Down Expand Up @@ -2464,7 +2464,7 @@ where
/// assert_eq!(reader.error_position(), 28);
/// assert_eq!(reader.buffer_position(), 41);
/// ```
pub fn get_ref(&self) -> &R {
pub const fn get_ref(&self) -> &R {
&self.reader.reader
}

Expand Down Expand Up @@ -3127,7 +3127,7 @@ impl<R: BufRead> IoReader<R> {
/// assert_eq!(reader.error_position(), 28);
/// assert_eq!(reader.buffer_position(), 41);
/// ```
pub fn get_ref(&self) -> &Reader<R> {
pub const fn get_ref(&self) -> &Reader<R> {
&self.reader
}
}
Expand Down Expand Up @@ -3194,7 +3194,7 @@ impl<'de> SliceReader<'de> {
/// assert_eq!(reader.error_position(), 28);
/// assert_eq!(reader.buffer_position(), 41);
/// ```
pub fn get_ref(&self) -> &Reader<&'de [u8]> {
pub const fn get_ref(&self) -> &Reader<&'de [u8]> {
&self.reader
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/de/simple_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ impl<'de, 'a> SimpleTypeDeserializer<'de, 'a> {

/// Constructor for tests
#[inline]
fn new(content: CowRef<'de, 'a, [u8]>, escaped: bool, decoder: Decoder) -> Self {
const fn new(content: CowRef<'de, 'a, [u8]>, escaped: bool, decoder: Decoder) -> Self {
Self {
content,
escaped,
Expand Down
2 changes: 1 addition & 1 deletion src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl Decoder {
///
/// [`decode`]: Self::decode
#[cfg(feature = "encoding")]
pub fn encoding(&self) -> &'static Encoding {
pub const fn encoding(&self) -> &'static Encoding {
self.encoding
}

Expand Down
6 changes: 3 additions & 3 deletions src/escape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ where
/// Behaves like [`resolve_xml_entity`] if feature is not enabled and as
/// [`resolve_html5_entity`] if enabled.
#[inline]
pub fn resolve_predefined_entity(entity: &str) -> Option<&'static str> {
pub const fn resolve_predefined_entity(entity: &str) -> Option<&'static str> {
#[cfg(not(feature = "escape-html"))]
{
resolve_xml_entity(entity)
Expand Down Expand Up @@ -314,7 +314,7 @@ pub fn resolve_predefined_entity(entity: &str) -> Option<&'static str> {
/// ```
///
/// [specification]: https://www.w3.org/TR/xml11/#sec-predefined-ent
pub fn resolve_xml_entity(entity: &str) -> Option<&'static str> {
pub const fn resolve_xml_entity(entity: &str) -> Option<&'static str> {
// match over strings are not allowed in const functions
let s = match entity.as_bytes() {
b"lt" => "<",
Expand All @@ -328,7 +328,7 @@ pub fn resolve_xml_entity(entity: &str) -> Option<&'static str> {
}

/// Resolves all HTML5 entities. For complete list see <https://dev.w3.org/html5/html-author/charref>.
pub fn resolve_html5_entity(entity: &str) -> Option<&'static str> {
pub const fn resolve_html5_entity(entity: &str) -> Option<&'static str> {
// imported from https://dev.w3.org/html5/html-author/charref
// match over strings are not allowed in const functions
//TODO: automate up-to-dating using https://html.spec.whatwg.org/entities.json
Expand Down
16 changes: 8 additions & 8 deletions src/events/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
use crate::errors::Result as XmlResult;
use crate::escape::{escape, resolve_predefined_entity, unescape_with};
use crate::name::QName;
use crate::reader::{is_whitespace, Reader};
use crate::utils::{write_byte_string, write_cow_string, Bytes};
use crate::reader::Reader;
use crate::utils::{is_whitespace, write_byte_string, write_cow_string, Bytes};
use std::fmt::{self, Debug, Display, Formatter};
use std::iter::FusedIterator;
use std::{borrow::Cow, ops::Range};
Expand Down Expand Up @@ -195,20 +195,20 @@ pub struct Attributes<'a> {
impl<'a> Attributes<'a> {
/// Internal constructor, used by `BytesStart`. Supplies data in reader's encoding
#[inline]
pub(crate) fn wrap(buf: &'a [u8], pos: usize, html: bool) -> Self {
pub(crate) const fn wrap(buf: &'a [u8], pos: usize, html: bool) -> Self {
Self {
bytes: buf,
state: IterState::new(pos, html),
}
}

/// Creates a new attribute iterator from a buffer.
pub fn new(buf: &'a str, pos: usize) -> Self {
pub const fn new(buf: &'a str, pos: usize) -> Self {
Self::wrap(buf.as_bytes(), pos, false)
}

/// Creates a new attribute iterator from a buffer, allowing HTML attribute syntax.
pub fn html(buf: &'a str, pos: usize) -> Self {
pub const fn html(buf: &'a str, pos: usize) -> Self {
Self::wrap(buf.as_bytes(), pos, true)
}

Expand Down Expand Up @@ -416,7 +416,7 @@ impl<T> Attr<T> {
impl<'a> Attr<&'a [u8]> {
/// Returns the key value
#[inline]
pub fn key(&self) -> QName<'a> {
pub const fn key(&self) -> QName<'a> {
QName(match self {
Attr::DoubleQ(key, _) => key,
Attr::SingleQ(key, _) => key,
Expand All @@ -429,7 +429,7 @@ impl<'a> Attr<&'a [u8]> {
///
/// [HTML specification]: https://www.w3.org/TR/2012/WD-html-markup-20120329/syntax.html#syntax-attr-empty
#[inline]
pub fn value(&self) -> &'a [u8] {
pub const fn value(&self) -> &'a [u8] {
match self {
Attr::DoubleQ(_, value) => value,
Attr::SingleQ(_, value) => value,
Expand Down Expand Up @@ -518,7 +518,7 @@ pub(crate) struct IterState {
}

impl IterState {
pub fn new(offset: usize, html: bool) -> Self {
pub const fn new(offset: usize, html: bool) -> Self {
Self {
state: State::Next(offset),
html,
Expand Down
45 changes: 6 additions & 39 deletions src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub mod attributes;
use encoding_rs::Encoding;
use std::borrow::Cow;
use std::fmt::{self, Debug, Formatter};
use std::mem::replace;
use std::ops::Deref;
use std::str::from_utf8;

Expand All @@ -50,12 +51,10 @@ use crate::escape::{
escape, minimal_escape, partial_escape, resolve_predefined_entity, unescape_with,
};
use crate::name::{LocalName, QName};
use crate::reader::{is_whitespace, name_len};
use crate::utils::write_cow_string;
#[cfg(feature = "serialize")]
use crate::utils::CowRef;
use crate::utils::{name_len, trim_xml_end, trim_xml_start, write_cow_string};
use attributes::{Attribute, Attributes};
use std::mem::replace;

/// Opening tag data (`Event::Start`), with optional attributes.
///
Expand All @@ -78,7 +77,7 @@ pub struct BytesStart<'a> {
impl<'a> BytesStart<'a> {
/// Internal constructor, used by `Reader`. Supplies data in reader's encoding
#[inline]
pub(crate) fn wrap(content: &'a [u8], name_len: usize) -> Self {
pub(crate) const fn wrap(content: &'a [u8], name_len: usize) -> Self {
BytesStart {
buf: Cow::Borrowed(content),
name_len,
Expand Down Expand Up @@ -406,7 +405,7 @@ impl<'a> BytesDecl<'a> {
}

/// Creates a `BytesDecl` from a `BytesStart`
pub fn from_start(start: BytesStart<'a>) -> Self {
pub const fn from_start(start: BytesStart<'a>) -> Self {
Self { content: start }
}

Expand Down Expand Up @@ -621,7 +620,7 @@ pub struct BytesEnd<'a> {
impl<'a> BytesEnd<'a> {
/// Internal constructor, used by `Reader`. Supplies data in reader's encoding
#[inline]
pub(crate) fn wrap(name: Cow<'a, [u8]>) -> Self {
pub(crate) const fn wrap(name: Cow<'a, [u8]>) -> Self {
BytesEnd { name }
}

Expand Down Expand Up @@ -1019,7 +1018,7 @@ pub struct BytesPI<'a> {
impl<'a> BytesPI<'a> {
/// Creates a new `BytesPI` from a byte sequence in the specified encoding.
#[inline]
pub(crate) fn wrap(content: &'a [u8], target_len: usize) -> Self {
pub(crate) const fn wrap(content: &'a [u8], target_len: usize) -> Self {
Self {
content: BytesStart::wrap(content, target_len),
}
Expand Down Expand Up @@ -1257,38 +1256,6 @@ fn str_cow_to_bytes<'a, C: Into<Cow<'a, str>>>(content: C) -> Cow<'a, [u8]> {
}
}

/// Returns a byte slice with leading XML whitespace bytes removed.
///
/// 'Whitespace' refers to the definition used by [`is_whitespace`].
const fn trim_xml_start(mut bytes: &[u8]) -> &[u8] {
// Note: A pattern matching based approach (instead of indexing) allows
// making the function const.
while let [first, rest @ ..] = bytes {
if is_whitespace(*first) {
bytes = rest;
} else {
break;
}
}
bytes
}

/// Returns a byte slice with trailing XML whitespace bytes removed.
///
/// 'Whitespace' refers to the definition used by [`is_whitespace`].
const fn trim_xml_end(mut bytes: &[u8]) -> &[u8] {
// Note: A pattern matching based approach (instead of indexing) allows
// making the function const.
while let [rest @ .., last] = bytes {
if is_whitespace(*last) {
bytes = rest;
} else {
break;
}
}
bytes
}

fn trim_cow<'a, F>(value: Cow<'a, [u8]>, trim: F) -> Cow<'a, [u8]>
where
F: FnOnce(&[u8]) -> &[u8],
Expand Down
10 changes: 5 additions & 5 deletions src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub struct QName<'a>(pub &'a [u8]);
impl<'a> QName<'a> {
/// Converts this name to an internal slice representation.
#[inline(always)]
pub fn into_inner(self) -> &'a [u8] {
pub const fn into_inner(self) -> &'a [u8] {
self.0
}

Expand Down Expand Up @@ -137,7 +137,7 @@ pub struct LocalName<'a>(&'a [u8]);
impl<'a> LocalName<'a> {
/// Converts this name to an internal slice representation.
#[inline(always)]
pub fn into_inner(self) -> &'a [u8] {
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
}
Expand Down Expand Up @@ -187,7 +187,7 @@ pub struct Prefix<'a>(&'a [u8]);
impl<'a> Prefix<'a> {
/// Extracts internal slice
#[inline(always)]
pub fn into_inner(self) -> &'a [u8] {
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
}
Expand Down Expand Up @@ -252,7 +252,7 @@ impl<'a> Namespace<'a> {
/// [non-normalized]: https://www.w3.org/TR/xml11/#AVNormalize
/// [IRI reference]: https://datatracker.ietf.org/doc/html/rfc3987
#[inline(always)]
pub fn into_inner(self) -> &'a [u8] {
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
//TODO: implement value normalization and use it when comparing namespaces
Expand Down Expand Up @@ -618,7 +618,7 @@ impl NamespaceResolver {
}

#[inline]
pub fn iter(&self) -> PrefixIter {
pub const fn iter(&self) -> PrefixIter {
PrefixIter {
resolver: self,
// We initialize the cursor to 2 to skip the two default namespaces xml: and xmlns:
Expand Down
4 changes: 2 additions & 2 deletions src/reader/async_tokio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use crate::events::Event;
use crate::name::{QName, ResolveResult};
use crate::reader::buffered_reader::impl_buffered_source;
use crate::reader::{
is_whitespace, BangType, ElementParser, NsReader, ParseState, Parser, PiParser, ReadTextResult,
Reader, Span,
BangType, ElementParser, NsReader, ParseState, Parser, PiParser, ReadTextResult, Reader, Span,
};
use crate::utils::is_whitespace;

/// A struct for read XML asynchronously from an [`AsyncBufRead`].
///
Expand Down
3 changes: 2 additions & 1 deletion src/reader/buffered_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use std::path::Path;
use crate::errors::{Error, Result};
use crate::events::Event;
use crate::name::QName;
use crate::reader::{is_whitespace, BangType, Parser, ReadTextResult, Reader, Span, XmlSource};
use crate::reader::{BangType, Parser, ReadTextResult, Reader, Span, XmlSource};
use crate::utils::is_whitespace;

macro_rules! impl_buffered_source {
($($lf:lifetime, $reader:tt, $async:ident, $await:ident)?) => {
Expand Down
Loading