diff --git a/CHANGELOG.md b/CHANGELOG.md index e1e3b68..aab98e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,25 @@ ## [Unreleased] +## [0.8.1] + +* Add types and methods to traverse nodes in depth-first order. +* Add methods to `Tree` to modify node attributes (not only appending). +* Make many (but not all) small methods `#[inline]`. +* Make some funcitions `#[must_use]`. + +### Added +* Add types and methods to traverse nodes in depth-first order. + + `tree::v7400::DepthFirstTraversed` type is added. + + `tree::v7400::DepthFirstTraverseSubtree` type is added. +* Add methods to `Tree` to modify node attributes (not only appending). + + `tree::v7400::Tree` has now three new methods: `get_attribute_mut()`, + `take_attributes_vec()`, and `set_attributes_vec()`. + +### Changed (non-breaking) +* Make many (but not all) small methods `#[inline]`. +* Make some funcitions `#[must_use]`. + ## [0.8.0] * Bump minimum supported Rust version to 1.56.0. @@ -15,18 +34,18 @@ and other commands should still run successfully with stable toolchain. * Bump internal dependencies. -## Added +### Added * `tree::v7400::NodeHandle::first_child_by_name()` is added. + `node.first_child_by_name(name)` returns the same result as `node.children_by_name(name).next()`. -## Fixed +### Fixed * Fixed incorrect attribute type value being written by the writer. -## Breaking changes +### Breaking changes * Bump minimum supported Rust version to 1.56.0. -## Non-breaking changes +### Non-breaking changes * Iterator types returned by `tree::v7400::NodeHandle::{children, children_by_name}` now have a name. + `NodeHandle::children()` returns `Children<'_>`. @@ -306,7 +325,8 @@ Totally rewritten. -[Unreleased]: +[Unreleased]: +[0.8.1]: [0.8.0]: [0.7.0]: [0.6.1]: diff --git a/Cargo.toml b/Cargo.toml index a379d8d..f2c9474 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "fbxcel" -version = "0.8.0" -authors = ["YOSHIOKA Takuma "] +version = "0.8.1" +authors = ["YOSHIOKA Takuma "] edition = "2021" rust-version = "1.56" license = "MIT OR Apache-2.0" diff --git a/src/low/fbx_header.rs b/src/low/fbx_header.rs index d875231..7b95dac 100644 --- a/src/low/fbx_header.rs +++ b/src/low/fbx_header.rs @@ -34,6 +34,7 @@ impl fmt::Display for HeaderError { } impl From for HeaderError { + #[inline] fn from(e: io::Error) -> Self { HeaderError::Io(e) } @@ -68,6 +69,8 @@ impl FbxHeader { } /// Returns FBX version. + #[inline] + #[must_use] pub fn version(self) -> FbxVersion { self.version } @@ -75,12 +78,16 @@ impl FbxHeader { /// Returns FBX parser version. /// /// Returns `None` if no parser supports the FBX version. + #[inline] + #[must_use] pub fn parser_version(self) -> Option { ParserVersion::from_fbx_version(self.version()) } /// Returns header length in bytes. - pub(crate) fn len(self) -> usize { + #[inline] + #[must_use] + pub(crate) const fn len(self) -> usize { /// FBX version length. const VERSION_LEN: usize = 4; diff --git a/src/low/v7400/array_attribute.rs b/src/low/v7400/array_attribute.rs index 121ed33..2b9a6b5 100644 --- a/src/low/v7400/array_attribute.rs +++ b/src/low/v7400/array_attribute.rs @@ -21,6 +21,8 @@ pub enum ArrayAttributeEncoding { impl ArrayAttributeEncoding { /// Creates a new `ArrayEncoding` from the given raw value. + #[inline] + #[must_use] pub(crate) fn from_u32(v: u32) -> Option { match v { 0 => Some(ArrayAttributeEncoding::Direct), @@ -32,6 +34,8 @@ impl ArrayAttributeEncoding { /// Returns the raw value. #[cfg(feature = "writer")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "writer")))] + #[inline] + #[must_use] pub(crate) fn to_u32(self) -> u32 { match self { ArrayAttributeEncoding::Direct => 0, @@ -42,6 +46,7 @@ impl ArrayAttributeEncoding { impl From for Compression { // Panics if the encoding is `Direct` (i.e. not compressed). + #[inline] fn from(v: ArrayAttributeEncoding) -> Self { match v { ArrayAttributeEncoding::Direct => unreachable!( diff --git a/src/low/v7400/attribute/type_.rs b/src/low/v7400/attribute/type_.rs index 5028ada..f74e65f 100644 --- a/src/low/v7400/attribute/type_.rs +++ b/src/low/v7400/attribute/type_.rs @@ -37,6 +37,7 @@ pub enum AttributeType { impl AttributeType { /// Creates an `AttributeType` from the given type code. + #[must_use] pub(crate) fn from_type_code(code: u8) -> Option { match code { b'C' => Some(AttributeType::Bool), @@ -59,6 +60,7 @@ impl AttributeType { /// Returns the type code. #[cfg(feature = "writer")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "writer")))] + #[must_use] pub(crate) fn type_code(self) -> u8 { match self { AttributeType::Bool => b'C', diff --git a/src/low/v7400/attribute/value.rs b/src/low/v7400/attribute/value.rs index 7d9f279..2b18328 100644 --- a/src/low/v7400/attribute/value.rs +++ b/src/low/v7400/attribute/value.rs @@ -48,6 +48,8 @@ pub enum AttributeValue { macro_rules! impl_val_getter { ($variant:ident, $ty_ret:ty, $opt_getter:ident, $opt_doc:expr, $res_getter:ident, $res_doc:expr,) => { #[doc = $opt_doc] + #[inline] + #[must_use] pub fn $opt_getter(&self) -> Option<$ty_ret> { match self { AttributeValue::$variant(v) => Some(*v), @@ -69,6 +71,8 @@ macro_rules! impl_val_getter { macro_rules! impl_ref_getter { ($variant:ident, $ty_ret:ty, $opt_getter:ident, $opt_doc:expr, $res_getter:ident, $res_doc:expr,) => { #[doc = $opt_doc] + #[inline] + #[must_use] pub fn $opt_getter(&self) -> Option<&$ty_ret> { match self { AttributeValue::$variant(v) => Some(v), @@ -88,6 +92,7 @@ macro_rules! impl_ref_getter { impl AttributeValue { /// Returns the value type. + #[must_use] pub fn type_(&self) -> AttributeType { match self { AttributeValue::Bool(_) => AttributeType::Bool, @@ -258,6 +263,7 @@ impl AttributeValue { macro_rules! impl_from { (direct: $ty:ty, $variant:ident) => { impl From<$ty> for AttributeValue { + #[inline] fn from(v: $ty) -> Self { AttributeValue::$variant(v.into()) } @@ -265,6 +271,7 @@ macro_rules! impl_from { }; (map: $ty:ty, $variant:ident, $arg:ident, $v:expr) => { impl From<$ty> for AttributeValue { + #[inline] fn from($arg: $ty) -> Self { AttributeValue::$variant($v) } diff --git a/src/low/v7400/node_header.rs b/src/low/v7400/node_header.rs index b1178f7..9b6fe58 100644 --- a/src/low/v7400/node_header.rs +++ b/src/low/v7400/node_header.rs @@ -20,6 +20,8 @@ pub(crate) struct NodeHeader { impl NodeHeader { /// Checks whether the entry indicates end of a node. + #[inline] + #[must_use] pub(crate) fn is_node_end(&self) -> bool { self.end_offset == 0 && self.num_attributes == 0 @@ -30,6 +32,8 @@ impl NodeHeader { /// Returns node end marker. #[cfg(feature = "writer")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "writer")))] + #[inline] + #[must_use] pub(crate) fn node_end() -> Self { Self { end_offset: 0, diff --git a/src/low/version.rs b/src/low/version.rs index a5cdc73..2a5f664 100644 --- a/src/low/version.rs +++ b/src/low/version.rs @@ -12,35 +12,45 @@ impl FbxVersion { pub const V7_5: Self = FbxVersion(7500); /// Creates a new `FbxVersion`. - pub(crate) fn new(version: u32) -> Self { + #[inline] + #[must_use] + pub(crate) const fn new(version: u32) -> Self { FbxVersion(version) } /// Returns the raw value. /// /// For example, `7400` for FBX 7.4. - pub(crate) fn raw(self) -> u32 { + #[inline] + #[must_use] + pub(crate) const fn raw(self) -> u32 { self.0 } /// Returns the major version. /// /// For example, `7` for FBX 7.4. - pub fn major(self) -> u32 { + #[inline] + #[must_use] + pub const fn major(self) -> u32 { self.raw() / 1000 } /// Returns the minor version. /// /// For example, `4` for FBX 7.4. - pub fn minor(self) -> u32 { + #[inline] + #[must_use] + pub const fn minor(self) -> u32 { (self.raw() % 1000) / 100 } /// Returns a tuple of the major and minor verison. /// /// For example, `(7, 4)` for FBX 7.4. - pub fn major_minor(self) -> (u32, u32) { + #[inline] + #[must_use] + pub const fn major_minor(self) -> (u32, u32) { let major = self.major(); let minor = self.minor(); (major, minor) diff --git a/src/pull_parser/any.rs b/src/pull_parser/any.rs index 63c68c4..d9f7048 100644 --- a/src/pull_parser/any.rs +++ b/src/pull_parser/any.rs @@ -24,6 +24,8 @@ pub enum AnyParser { impl AnyParser { /// Returns the parser version. + #[inline] + #[must_use] pub fn parser_version(&self) -> ParserVersion { match self { AnyParser::V7400(_) => pull_parser::v7400::Parser::::PARSER_VERSION, @@ -31,6 +33,8 @@ impl AnyParser { } /// Returns the FBX version. + #[inline] + #[must_use] pub fn fbx_version(&self) -> FbxVersion { match self { AnyParser::V7400(parser) => parser.fbx_version(), diff --git a/src/pull_parser/any/error.rs b/src/pull_parser/any/error.rs index f7ce9cc..1c167cb 100644 --- a/src/pull_parser/any/error.rs +++ b/src/pull_parser/any/error.rs @@ -18,6 +18,7 @@ pub enum Error { } impl error::Error for Error { + #[inline] fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { Error::Header(e) => Some(e), @@ -36,6 +37,7 @@ impl fmt::Display for Error { } impl From for Error { + #[inline] fn from(e: HeaderError) -> Self { Error::Header(e) } diff --git a/src/pull_parser/error.rs b/src/pull_parser/error.rs index 01b9914..dea06f3 100644 --- a/src/pull_parser/error.rs +++ b/src/pull_parser/error.rs @@ -28,26 +28,36 @@ pub struct Error { impl Error { /// Returns the error kind. + #[inline] + #[must_use] pub fn kind(&self) -> ErrorKind { self.repr.error.kind() } /// Returns a reference to the inner error container. + #[inline] + #[must_use] pub fn get_ref(&self) -> &ErrorContainer { &self.repr.error } /// Returns a reference to the inner error if the type matches. + #[inline] + #[must_use] pub fn downcast_ref(&self) -> Option<&T> { self.repr.error.as_error().downcast_ref::() } /// Returns the syntactic position if available. + #[inline] + #[must_use] pub fn position(&self) -> Option<&SyntacticPosition> { self.repr.position.as_ref() } /// Creates a new `Error` with the given syntactic position info. + #[inline] + #[must_use] pub(crate) fn with_position(error: ErrorContainer, position: SyntacticPosition) -> Self { Self { repr: Box::new(Repr::with_position(error, position)), @@ -55,6 +65,8 @@ impl Error { } /// Sets the syntactic position and returns the new error. + #[inline] + #[must_use] pub(crate) fn and_position(mut self, position: SyntacticPosition) -> Self { self.repr.position = Some(position); self @@ -62,12 +74,14 @@ impl Error { } impl fmt::Display for Error { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.repr.error.fmt(f) } } impl error::Error for Error { + #[inline] fn source(&self) -> Option<&(dyn error::Error + 'static)> { self.repr.error.source() } @@ -77,6 +91,7 @@ impl From for Error where T: Into, { + #[inline] fn from(e: T) -> Self { Error { repr: Box::new(Repr::new(e.into())), @@ -95,6 +110,8 @@ struct Repr { impl Repr { /// Creates a new `Repr`. + #[inline] + #[must_use] pub(crate) fn new(error: ErrorContainer) -> Self { Self { error, @@ -103,6 +120,8 @@ impl Repr { } /// Creates a new `Repr` with the given syntactic position info. + #[inline] + #[must_use] pub(crate) fn with_position(error: ErrorContainer, position: SyntacticPosition) -> Self { Self { error, @@ -156,6 +175,7 @@ pub enum ErrorContainer { impl ErrorContainer { /// Returns the error kind of the error. + #[must_use] pub fn kind(&self) -> ErrorKind { match self { ErrorContainer::Data(_) => ErrorKind::Data, @@ -166,6 +186,7 @@ impl ErrorContainer { } /// Returns `&dyn std::error::Error`. + #[must_use] pub fn as_error(&self) -> &(dyn 'static + error::Error) { match self { ErrorContainer::Data(e) => e, @@ -177,6 +198,8 @@ impl ErrorContainer { } impl error::Error for ErrorContainer { + #[inline] + #[must_use] fn source(&self) -> Option<&(dyn error::Error + 'static)> { Some(self.as_error()) } @@ -194,24 +217,28 @@ impl fmt::Display for ErrorContainer { } impl From for ErrorContainer { + #[inline] fn from(e: io::Error) -> Self { ErrorContainer::Io(e) } } impl From for ErrorContainer { + #[inline] fn from(e: DataError) -> Self { ErrorContainer::Data(e) } } impl From for ErrorContainer { + #[inline] fn from(e: OperationError) -> Self { ErrorContainer::Operation(e) } } impl From for ErrorContainer { + #[inline] fn from(e: Warning) -> Self { ErrorContainer::Warning(e) } diff --git a/src/pull_parser/position.rs b/src/pull_parser/position.rs index 3532516..59a1acd 100644 --- a/src/pull_parser/position.rs +++ b/src/pull_parser/position.rs @@ -24,11 +24,15 @@ pub struct SyntacticPosition { impl SyntacticPosition { /// Returns the byte position. + #[inline] + #[must_use] pub fn byte_pos(&self) -> u64 { self.byte_pos } /// Returns the beginning byte position of the node or attribute. + #[inline] + #[must_use] pub fn component_byte_pos(&self) -> u64 { self.component_byte_pos } @@ -37,11 +41,15 @@ impl SyntacticPosition { /// /// This is a vector of pairs of node indices in siblings (i.e. the number /// of preceding siblings) and node names. + #[inline] + #[must_use] pub fn node_path(&self) -> &[(usize, String)] { &self.node_path } /// Returns the node attribute index (if the position points an attribute). + #[inline] + #[must_use] pub fn attribute_index(&self) -> Option { self.attribute_index } diff --git a/src/pull_parser/reader.rs b/src/pull_parser/reader.rs index 8c4eed7..8ba84e8 100644 --- a/src/pull_parser/reader.rs +++ b/src/pull_parser/reader.rs @@ -36,6 +36,7 @@ pub trait ParserSource: Sized + io::Read { /// `self.stream_position().unwrap()`, but this is fallible and /// can be inefficient. /// Use of [`PositionCacheReader`] is reccomended. + #[must_use] fn position(&self) -> u64; /// Skips (seeks formward) the given size. @@ -96,14 +97,17 @@ pub trait ParserSource: Sized + io::Read { } impl ParserSource for &mut R { + #[inline] fn position(&self) -> u64 { (**self).position() } + #[inline] fn skip_distance(&mut self, distance: u64) -> io::Result<()> { (**self).skip_distance(distance) } + #[inline] fn skip_to(&mut self, pos: u64) -> io::Result<()> { (**self).skip_to(pos) } diff --git a/src/pull_parser/reader/position_cache.rs b/src/pull_parser/reader/position_cache.rs index f586e93..2e21548 100644 --- a/src/pull_parser/reader/position_cache.rs +++ b/src/pull_parser/reader/position_cache.rs @@ -21,6 +21,8 @@ pub struct PositionCacheReader { impl PositionCacheReader { /// Creates a new `PositionCacheReader`. + #[inline] + #[must_use] pub fn new(inner: R) -> Self { Self { inner, position: 0 } } @@ -41,6 +43,8 @@ impl PositionCacheReader { /// .expect("Should never fail"); /// assert_eq!(reader.position(), len + 42); /// ``` + #[inline] + #[must_use] pub fn with_offset(inner: R, offset: usize) -> Self { Self { inner, @@ -49,11 +53,15 @@ impl PositionCacheReader { } /// Unwraps the wrapper and returns the inner reader. + #[inline] + #[must_use] pub fn into_inner(self) -> R { self.inner } /// Returns the current position. + #[inline] + #[must_use] pub fn position(&self) -> usize { self.position } @@ -108,10 +116,12 @@ impl io::Read for PositionCacheReader { } impl io::BufRead for PositionCacheReader { + #[inline] fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() } + #[inline] fn consume(&mut self, amt: usize) { self.inner.consume(amt); self.advance(amt); @@ -119,6 +129,7 @@ impl io::BufRead for PositionCacheReader { } impl ParserSource for PositionCacheReader { + #[inline] fn position(&self) -> u64 { self.position() as u64 } diff --git a/src/pull_parser/reader/source.rs b/src/pull_parser/reader/source.rs index dae0ccf..a9eaf52 100644 --- a/src/pull_parser/reader/source.rs +++ b/src/pull_parser/reader/source.rs @@ -20,6 +20,8 @@ pub struct PlainSource { impl PlainSource { /// Creates a new `PlainSource`. + #[inline] + #[must_use] pub fn new(inner: R) -> Self { Self { inner: PositionCacheReader::new(inner), @@ -44,6 +46,8 @@ impl PlainSource { /// .expect("Should never fail"); /// assert_eq!(reader.position(), len + 42); /// ``` + #[inline] + #[must_use] pub fn with_offset(inner: R, offset: usize) -> Self { Self { inner: PositionCacheReader::with_offset(inner, offset), @@ -52,26 +56,31 @@ impl PlainSource { } impl io::Read for PlainSource { + #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } } impl io::BufRead for PlainSource { + #[inline] fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() } + #[inline] fn consume(&mut self, amt: usize) { self.inner.consume(amt) } } impl ParserSource for PlainSource { + #[inline] fn position(&self) -> u64 { self.inner.position() as u64 } + #[inline] fn skip_distance(&mut self, distance: u64) -> io::Result<()> { // NOTE: `self.inner.take(distance)` is E0507. io::copy( @@ -97,6 +106,8 @@ pub struct SeekableSource { impl SeekableSource { /// Creates a new `SeekableSource`. + #[inline] + #[must_use] pub fn new(inner: R) -> Self { Self { inner: PositionCacheReader::new(inner), @@ -121,6 +132,8 @@ impl SeekableSource { /// .expect("Should never fail"); /// assert_eq!(reader.position(), len + 42); /// ``` + #[inline] + #[must_use] pub fn with_offset(inner: R, offset: usize) -> Self { Self { inner: PositionCacheReader::with_offset(inner, offset), @@ -129,26 +142,31 @@ impl SeekableSource { } impl io::Read for SeekableSource { + #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } } impl io::BufRead for SeekableSource { + #[inline] fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() } + #[inline] fn consume(&mut self, amt: usize) { self.inner.consume(amt) } } impl ParserSource for SeekableSource { + #[inline] fn position(&self) -> u64 { self.inner.position() as u64 } + #[inline] fn skip_distance(&mut self, distance: u64) -> io::Result<()> { // `PositionCacheReader::skip_distance` will be available only when // `R: io::Seek`, and it will use `io::Seek::seek` efficiently. diff --git a/src/pull_parser/v7400/attribute.rs b/src/pull_parser/v7400/attribute.rs index 87eab5d..4232b04 100644 --- a/src/pull_parser/v7400/attribute.rs +++ b/src/pull_parser/v7400/attribute.rs @@ -37,6 +37,7 @@ pub struct Attributes<'a, R> { impl<'a, R: 'a + ParserSource> Attributes<'a, R> { /// Creates a new `Attributes`. + #[must_use] pub(crate) fn from_parser(parser: &'a mut Parser) -> Self { let total_count = parser.current_attributes_count(); let pos = parser.reader().position(); @@ -49,11 +50,15 @@ impl<'a, R: 'a + ParserSource> Attributes<'a, R> { } /// Returns the total number of attributes. + #[inline] + #[must_use] pub fn total_count(&self) -> u64 { self.total_count } /// Returns the number of the rest attributes. + #[inline] + #[must_use] pub fn rest_count(&self) -> u64 { self.rest_count } @@ -319,6 +324,8 @@ impl<'a, R: 'a + ParserSource> Attributes<'a, R> { } /// Returns the syntactic position of the attribute currently reading. + #[inline] + #[must_use] fn position(&self, start_pos: u64, index: usize) -> SyntacticPosition { SyntacticPosition { component_byte_pos: start_pos, @@ -328,6 +335,7 @@ impl<'a, R: 'a + ParserSource> Attributes<'a, R> { } /// Creates an iterator emitting attribute values. + #[inline] pub fn iter(&mut self, loaders: I) -> iter::BorrowedIter<'_, 'a, R, I::IntoIter> where V: LoadAttribute, @@ -337,6 +345,7 @@ impl<'a, R: 'a + ParserSource> Attributes<'a, R> { } /// Creates an iterator emitting attribute values with buffered I/O. + #[inline] pub fn iter_buffered( &mut self, loaders: I, @@ -350,6 +359,7 @@ impl<'a, R: 'a + ParserSource> Attributes<'a, R> { } /// Creates an iterator emitting attribute values. + #[inline] pub fn into_iter(self, loaders: I) -> iter::OwnedIter<'a, R, I::IntoIter> where V: LoadAttribute, @@ -359,6 +369,7 @@ impl<'a, R: 'a + ParserSource> Attributes<'a, R> { } /// Creates an iterator emitting attribute values with buffered I/O. + #[inline] pub fn into_iter_buffered(self, loaders: I) -> iter::OwnedIterBuffered<'a, R, I::IntoIter> where R: io::BufRead, diff --git a/src/pull_parser/v7400/attribute/array.rs b/src/pull_parser/v7400/attribute/array.rs index 7234251..675e4a8 100644 --- a/src/pull_parser/v7400/attribute/array.rs +++ b/src/pull_parser/v7400/attribute/array.rs @@ -63,6 +63,8 @@ where R: io::Read, { /// Creates a new `ArrayAttributeValues`. + #[inline] + #[must_use] pub(crate) fn new(reader: R, total_elements: u32) -> Self { Self { reader, @@ -74,6 +76,8 @@ where } /// Returns whether an error happened or not. + #[inline] + #[must_use] pub(crate) fn has_error(&self) -> bool { self.has_error } @@ -106,6 +110,7 @@ macro_rules! impl_array_attr_values { } } + #[inline] fn size_hint(&self) -> (usize, Option) { (0, Some(self.rest_elements as usize)) } @@ -138,6 +143,8 @@ pub(crate) struct BooleanArrayAttributeValues { impl BooleanArrayAttributeValues { /// Creates a new `BooleanArrayAttributeValues`. + #[inline] + #[must_use] pub(crate) fn new(reader: R, total_elements: u32) -> Self { Self { reader, @@ -150,11 +157,15 @@ impl BooleanArrayAttributeValues { /// Returns whether the attribute has incorrect boolean value /// representation. + #[inline] + #[must_use] pub(crate) fn has_incorrect_boolean_value(&self) -> bool { self.has_incorrect_boolean_value } /// Returns whether an error happened or not. + #[inline] + #[must_use] pub(crate) fn has_error(&self) -> bool { self.has_error } @@ -188,6 +199,7 @@ impl Iterator for BooleanArrayAttributeValues { } } + #[inline] fn size_hint(&self) -> (usize, Option) { (0, Some(self.rest_elements as usize)) } diff --git a/src/pull_parser/v7400/attribute/iter.rs b/src/pull_parser/v7400/attribute/iter.rs index fb63547..e5af7b8 100644 --- a/src/pull_parser/v7400/attribute/iter.rs +++ b/src/pull_parser/v7400/attribute/iter.rs @@ -9,6 +9,7 @@ use crate::pull_parser::{ }; /// Creates size hint from the given attributes and loaders. +#[must_use] fn make_size_hint_for_attrs( attributes: &Attributes<'_, R>, loaders: &impl Iterator, @@ -26,6 +27,7 @@ where } /// Loads the next attrbute. +#[must_use] fn load_next( attributes: &mut Attributes<'_, R>, loaders: &mut impl Iterator, @@ -39,6 +41,7 @@ where } /// Loads the next attrbute with buffered I/O. +#[must_use] fn load_next_buffered( attributes: &mut Attributes<'_, R>, loaders: &mut impl Iterator, @@ -67,6 +70,8 @@ where V: LoadAttribute, { /// Creates a new iterator. + #[inline] + #[must_use] pub(crate) fn new(attributes: &'a mut Attributes<'r, R>, loaders: I) -> Self { Self { attributes, @@ -83,10 +88,12 @@ where { type Item = Result; + #[inline] fn next(&mut self) -> Option { load_next(self.attributes, &mut self.loaders) } + #[inline] fn size_hint(&self) -> (usize, Option) { make_size_hint_for_attrs(self.attributes, &self.loaders) } @@ -116,6 +123,8 @@ where V: LoadAttribute, { /// Creates a new iterator. + #[inline] + #[must_use] pub(crate) fn new(attributes: &'a mut Attributes<'r, R>, loaders: I) -> Self { Self { attributes, @@ -132,10 +141,12 @@ where { type Item = Result; + #[inline] fn next(&mut self) -> Option { load_next_buffered(self.attributes, &mut self.loaders) } + #[inline] fn size_hint(&self) -> (usize, Option) { make_size_hint_for_attrs(self.attributes, &self.loaders) } @@ -165,6 +176,8 @@ where V: LoadAttribute, { /// Creates a new `Iter`. + #[inline] + #[must_use] pub(crate) fn new(attributes: Attributes<'r, R>, loaders: I) -> Self { Self { attributes, @@ -181,10 +194,12 @@ where { type Item = Result; + #[inline] fn next(&mut self) -> Option { load_next(&mut self.attributes, &mut self.loaders) } + #[inline] fn size_hint(&self) -> (usize, Option) { make_size_hint_for_attrs(&self.attributes, &self.loaders) } @@ -214,6 +229,8 @@ where V: LoadAttribute, { /// Creates a new iterator. + #[inline] + #[must_use] pub(crate) fn new(attributes: Attributes<'r, R>, loaders: I) -> Self { Self { attributes, @@ -230,10 +247,12 @@ where { type Item = Result; + #[inline] fn next(&mut self) -> Option { load_next_buffered(&mut self.attributes, &mut self.loaders) } + #[inline] fn size_hint(&self) -> (usize, Option) { make_size_hint_for_attrs(&self.attributes, &self.loaders) } diff --git a/src/pull_parser/v7400/attribute/loader.rs b/src/pull_parser/v7400/attribute/loader.rs index 10e7440..d47ef9b 100644 --- a/src/pull_parser/v7400/attribute/loader.rs +++ b/src/pull_parser/v7400/attribute/loader.rs @@ -110,6 +110,7 @@ pub trait LoadAttribute: Sized + fmt::Debug { /// Loads binary value on buffered reader. /// /// This method should return error when the given reader returned error. + #[inline] fn load_binary_buffered(self, reader: impl io::BufRead, len: u64) -> Result { self.load_binary(reader, len) } @@ -124,6 +125,7 @@ pub trait LoadAttribute: Sized + fmt::Debug { /// Loads string value on buffered reader. /// /// This method should return error when the given reader returned error. + #[inline] fn load_string_buffered(self, reader: impl io::BufRead, len: u64) -> Result { self.load_string(reader, len) } diff --git a/src/pull_parser/v7400/attribute/loaders/direct.rs b/src/pull_parser/v7400/attribute/loaders/direct.rs index 8715792..2707127 100644 --- a/src/pull_parser/v7400/attribute/loaders/direct.rs +++ b/src/pull_parser/v7400/attribute/loaders/direct.rs @@ -14,34 +14,42 @@ pub struct DirectLoader; impl LoadAttribute for DirectLoader { type Output = AttributeValue; + #[inline] fn expecting(&self) -> String { "any type".into() } + #[inline] fn load_bool(self, v: bool) -> Result { Ok(AttributeValue::Bool(v)) } + #[inline] fn load_i16(self, v: i16) -> Result { Ok(AttributeValue::I16(v)) } + #[inline] fn load_i32(self, v: i32) -> Result { Ok(AttributeValue::I32(v)) } + #[inline] fn load_i64(self, v: i64) -> Result { Ok(AttributeValue::I64(v)) } + #[inline] fn load_f32(self, v: f32) -> Result { Ok(AttributeValue::F32(v)) } + #[inline] fn load_f64(self, v: f64) -> Result { Ok(AttributeValue::F64(v)) } + #[inline] fn load_seq_bool( self, iter: impl Iterator>, @@ -50,6 +58,7 @@ impl LoadAttribute for DirectLoader { Ok(AttributeValue::ArrBool(iter.collect::>()?)) } + #[inline] fn load_seq_i32( self, iter: impl Iterator>, @@ -58,6 +67,7 @@ impl LoadAttribute for DirectLoader { Ok(AttributeValue::ArrI32(iter.collect::>()?)) } + #[inline] fn load_seq_i64( self, iter: impl Iterator>, @@ -66,6 +76,7 @@ impl LoadAttribute for DirectLoader { Ok(AttributeValue::ArrI64(iter.collect::>()?)) } + #[inline] fn load_seq_f32( self, iter: impl Iterator>, @@ -74,6 +85,7 @@ impl LoadAttribute for DirectLoader { Ok(AttributeValue::ArrF32(iter.collect::>()?)) } + #[inline] fn load_seq_f64( self, iter: impl Iterator>, @@ -82,12 +94,14 @@ impl LoadAttribute for DirectLoader { Ok(AttributeValue::ArrF64(iter.collect::>()?)) } + #[inline] fn load_binary(self, mut reader: impl io::Read, len: u64) -> Result { let mut buf = Vec::with_capacity(len as usize); reader.read_to_end(&mut buf)?; Ok(AttributeValue::Binary(buf)) } + #[inline] fn load_string(self, mut reader: impl io::Read, len: u64) -> Result { let mut buf = String::with_capacity(len as usize); reader.read_to_string(&mut buf)?; diff --git a/src/pull_parser/v7400/attribute/loaders/single.rs b/src/pull_parser/v7400/attribute/loaders/single.rs index e03ed63..1d005d1 100644 --- a/src/pull_parser/v7400/attribute/loaders/single.rs +++ b/src/pull_parser/v7400/attribute/loaders/single.rs @@ -20,6 +20,7 @@ macro_rules! impl_load_attribute_for_primitives { $expecting_type.into() } + #[inline] fn $method_name(self, v: $ty) -> Result { Ok(v) } @@ -50,6 +51,7 @@ macro_rules! impl_load_attribute_for_arrays { $expecting_type.into() } + #[inline] fn $method_name( self, iter: impl Iterator>, @@ -78,6 +80,7 @@ impl LoadAttribute for BinaryLoader { "binary".into() } + #[inline] fn load_binary(self, mut reader: impl io::Read, len: u64) -> Result { let mut buf = Vec::with_capacity(len as usize); reader.read_to_end(&mut buf)?; @@ -96,6 +99,7 @@ impl LoadAttribute for StringLoader { "string".into() } + #[inline] fn load_string(self, mut reader: impl io::Read, len: u64) -> Result { let mut buf = String::with_capacity(len as usize); reader.read_to_string(&mut buf)?; diff --git a/src/pull_parser/v7400/attribute/loaders/type_.rs b/src/pull_parser/v7400/attribute/loaders/type_.rs index cdc3eef..d3e9a3c 100644 --- a/src/pull_parser/v7400/attribute/loaders/type_.rs +++ b/src/pull_parser/v7400/attribute/loaders/type_.rs @@ -17,34 +17,42 @@ pub struct TypeLoader; impl LoadAttribute for TypeLoader { type Output = AttributeType; + #[inline] fn expecting(&self) -> String { "any type".into() } + #[inline] fn load_bool(self, _: bool) -> Result { Ok(AttributeType::Bool) } + #[inline] fn load_i16(self, _: i16) -> Result { Ok(AttributeType::I16) } + #[inline] fn load_i32(self, _: i32) -> Result { Ok(AttributeType::I32) } + #[inline] fn load_i64(self, _: i64) -> Result { Ok(AttributeType::I64) } + #[inline] fn load_f32(self, _: f32) -> Result { Ok(AttributeType::F32) } + #[inline] fn load_f64(self, _: f64) -> Result { Ok(AttributeType::F64) } + #[inline] fn load_seq_bool( self, _: impl Iterator>, @@ -53,6 +61,7 @@ impl LoadAttribute for TypeLoader { Ok(AttributeType::ArrBool) } + #[inline] fn load_seq_i32( self, _: impl Iterator>, @@ -61,6 +70,7 @@ impl LoadAttribute for TypeLoader { Ok(AttributeType::ArrI32) } + #[inline] fn load_seq_i64( self, _: impl Iterator>, @@ -69,6 +79,7 @@ impl LoadAttribute for TypeLoader { Ok(AttributeType::ArrI64) } + #[inline] fn load_seq_f32( self, _: impl Iterator>, @@ -77,6 +88,7 @@ impl LoadAttribute for TypeLoader { Ok(AttributeType::ArrF32) } + #[inline] fn load_seq_f64( self, _: impl Iterator>, @@ -85,10 +97,12 @@ impl LoadAttribute for TypeLoader { Ok(AttributeType::ArrF64) } + #[inline] fn load_binary(self, _: impl io::Read, _len: u64) -> Result { Ok(AttributeType::Binary) } + #[inline] fn load_string(self, _: impl io::Read, _len: u64) -> Result { Ok(AttributeType::String) } diff --git a/src/pull_parser/v7400/event.rs b/src/pull_parser/v7400/event.rs index 2929897..b61675b 100644 --- a/src/pull_parser/v7400/event.rs +++ b/src/pull_parser/v7400/event.rs @@ -31,16 +31,22 @@ pub struct StartNode<'a, R> { impl<'a, R: 'a + ParserSource> StartNode<'a, R> { /// Creates a new `StartNode`. + #[inline] + #[must_use] pub(crate) fn new(parser: &'a mut Parser) -> Self { Self { parser } } /// Returns the node name. + #[inline] + #[must_use] pub fn name(&self) -> &str { self.parser.current_node_name() } /// Returns node attributes reader. + #[inline] + #[must_use] pub fn attributes(self) -> Attributes<'a, R> { Attributes::from_parser(self.parser) } diff --git a/src/pull_parser/v7400/parser.rs b/src/pull_parser/v7400/parser.rs index 7dcafee..c3e136f 100644 --- a/src/pull_parser/v7400/parser.rs +++ b/src/pull_parser/v7400/parser.rs @@ -21,6 +21,7 @@ type WarningHandler = Box Result<()>>; /// Creates a new [`Parser`] from the given reader. /// /// Returns an error if the given FBX version in unsupported. +#[inline] pub fn from_reader(header: FbxHeader, reader: R) -> Result>> where R: io::Read, @@ -34,6 +35,7 @@ where /// Creates a new [`Parser`] from the given seekable reader. /// /// Returns an error if the given FBX version in unsupported. +#[inline] pub fn from_seekable_reader(header: FbxHeader, reader: R) -> Result>> where R: io::Read + io::Seek, @@ -104,6 +106,7 @@ impl Parser { /// ``` /// /// [syntactic position]: `SyntacticPosition` + #[inline] pub fn set_warning_handler(&mut self, warning_handler: F) where F: 'static + FnMut(Warning, &SyntacticPosition) -> Result<()>, @@ -112,11 +115,15 @@ impl Parser { } /// Returns a mutable reference to the inner reader. + #[inline] + #[must_use] pub(crate) fn reader(&mut self) -> &mut R { &mut self.reader } /// Returns FBX version. + #[inline] + #[must_use] pub fn fbx_version(&self) -> FbxVersion { self.state.fbx_version } @@ -126,6 +133,8 @@ impl Parser { /// # Panics /// /// This panics if there are no open nodes. + #[inline] + #[must_use] pub fn current_node_name(&self) -> &str { self.state .current_node() @@ -135,6 +144,8 @@ impl Parser { } /// Returns the number of attributes of the current node. + #[inline] + #[must_use] pub(crate) fn current_attributes_count(&self) -> u64 { self.state .current_node() @@ -145,6 +156,8 @@ impl Parser { /// Returns current node depth. /// /// Implicit root node is considered to be depth 0. + #[inline] + #[must_use] pub fn current_depth(&self) -> usize { self.state.started_nodes.len() } @@ -162,6 +175,7 @@ impl Parser { } /// Reads the given type from the underlying reader. + #[inline] pub(crate) fn parse(&mut self) -> Result { T::read_from_parser(self) } @@ -384,6 +398,7 @@ impl Parser { } /// Sets the parser to aborted state. + #[inline] pub(crate) fn set_aborted(&mut self, pos: SyntacticPosition) { self.state.health = Health::Aborted(pos); } @@ -456,6 +471,7 @@ impl Parser { /// Returns the syntactic position of the current node. /// /// Note that this allocates memory. + #[inline] pub fn position(&self) -> SyntacticPosition { let byte_pos = self.reader.position(); if self.state.current_node().is_none() { @@ -522,6 +538,8 @@ impl Parser { /// let _ = parser.next_event(); /// assert!(parser.is_used(), "Parser emitted an event"); /// ``` + #[inline] + #[must_use] pub fn is_used(&self) -> bool { self.state.last_event_kind.is_some() } @@ -575,6 +593,8 @@ struct State { impl State { /// Creates a new `State` for the given FBX version. + #[inline] + #[must_use] fn new(fbx_version: FbxVersion) -> Self { Self { fbx_version, @@ -586,16 +606,22 @@ impl State { } /// Returns health of the parser. + #[inline] + #[must_use] fn health(&self) -> &Health { &self.health } /// Returns info about current node (except for implicit root node). + #[inline] + #[must_use] fn current_node(&self) -> Option<&StartedNode> { self.started_nodes.last() } /// Returns the last event kind. + #[inline] + #[must_use] fn last_event_kind(&self) -> Option { self.last_event_kind } diff --git a/src/pull_parser/v7400/read.rs b/src/pull_parser/v7400/read.rs index b4fe571..afe3bfd 100644 --- a/src/pull_parser/v7400/read.rs +++ b/src/pull_parser/v7400/read.rs @@ -13,6 +13,7 @@ pub(crate) trait FromReader: Sized { } impl FromReader for u8 { + #[inline] fn from_reader(reader: &mut impl io::Read) -> Result { Ok(reader.read_u8()?) } @@ -22,6 +23,7 @@ impl FromReader for u8 { macro_rules! impl_from_reader_for_primitives { ($ty:ty, $read_method:ident) => { impl FromReader for $ty { + #[inline] fn from_reader(reader: &mut impl io::Read) -> Result { Ok(reader.$read_method::()?) } @@ -45,6 +47,7 @@ pub(crate) trait FromParser: Sized { } impl FromParser for T { + #[inline] fn read_from_parser(parser: &mut Parser) -> Result { FromReader::from_reader(parser.reader()) } diff --git a/src/pull_parser/version.rs b/src/pull_parser/version.rs index 4c13d97..904ac53 100644 --- a/src/pull_parser/version.rs +++ b/src/pull_parser/version.rs @@ -17,6 +17,7 @@ pub enum ParserVersion { impl ParserVersion { /// Returns the parser version corresponding to the given FBX version. + #[must_use] pub fn from_fbx_version(fbx_version: FbxVersion) -> Option { let raw = fbx_version.raw(); match raw { diff --git a/src/tree/any.rs b/src/tree/any.rs index 2186840..9491894 100644 --- a/src/tree/any.rs +++ b/src/tree/any.rs @@ -62,6 +62,8 @@ impl AnyTree { } /// Returns the FBX version of the document the tree came from. + #[inline] + #[must_use] pub fn fbx_version(&self) -> FbxVersion { match self { Self::V7400(ver, _, _) => *ver, diff --git a/src/tree/any/error.rs b/src/tree/any/error.rs index 19530be..7cccff4 100644 --- a/src/tree/any/error.rs +++ b/src/tree/any/error.rs @@ -40,18 +40,21 @@ impl fmt::Display for Error { } impl From for Error { + #[inline] fn from(e: pull_parser::any::Error) -> Self { Error::ParserCreation(e) } } impl From for Error { + #[inline] fn from(e: pull_parser::Error) -> Self { Error::Parser(e) } } impl From for Error { + #[inline] fn from(e: tree::v7400::LoadError) -> Self { Error::Tree(e.into()) } diff --git a/src/tree/v7400.rs b/src/tree/v7400.rs index 2620b06..3edb2e7 100644 --- a/src/tree/v7400.rs +++ b/src/tree/v7400.rs @@ -36,11 +36,15 @@ pub struct Tree { impl Tree { /// Returns the root node. + #[inline] + #[must_use] pub fn root(&self) -> NodeHandle<'_> { NodeHandle::new(self, self.root_id) } /// Creates a new `Tree`. + #[inline] + #[must_use] fn new( arena: Arena, node_names: StringInterner>, @@ -58,6 +62,7 @@ impl Tree { /// # Panics /// /// Panics if a node with the given node ID does not exist in the tree. + #[must_use] pub(crate) fn node(&self, node_id: NodeId) -> &indextree::Node { self.arena.get(node_id.raw()).unwrap_or_else(|| { panic!( @@ -72,6 +77,7 @@ impl Tree { /// # Panics /// /// Panics if the given symbol is not used in the tree. + #[must_use] pub(crate) fn resolve_node_name(&self, sym: NodeNameSym) -> &str { self.node_names .resolve(sym) @@ -79,11 +85,13 @@ impl Tree { } /// Returns node name symbol if available. + #[must_use] pub(crate) fn node_name_sym(&self, name: &str) -> Option { self.node_names.get(name) } /// Checks whether or not the given node ID is used in the tree. + #[must_use] pub(crate) fn contains_node(&self, node_id: NodeId) -> bool { self.arena.get(node_id.raw()).is_some() } @@ -162,6 +170,42 @@ impl Tree { node.get_mut().append_attribute(v) } + /// Returns a mutable reference to the node attribute at the given index. + /// + /// # Panics + /// + /// Panics if the given node ID is invalid (i.e. not used or root node). + #[must_use] + pub fn get_attribute_mut(&mut self, node_id: NodeId, i: usize) -> Option<&mut AttributeValue> { + let node = self.arena.get_mut(node_id.raw()).expect("Invalid node ID"); + node.get_mut().get_attribute_mut(i) + } + + /// Takes all attributes as a `Vec`. + /// + /// After calling this, the node will have no attributes (until other values are set). + /// + /// # Panics + /// + /// Panics if the given node ID is invalid (i.e. not used or root node). + pub fn take_attributes_vec(&mut self, node_id: NodeId) -> Vec { + let node = self.arena.get_mut(node_id.raw()).expect("Invalid node ID"); + node.get_mut().replace_attributes(Default::default()) + } + + /// Sets the given `Vec` of attribute values as the node attributes. + /// + /// After calling this, the node will have only the given attributes. + /// + /// # Panics + /// + /// Panics if the given node ID is invalid (i.e. not used or root node). + pub fn set_attributes_vec(&mut self, node_id: NodeId, new: Vec) { + let node = self.arena.get_mut(node_id.raw()).expect("Invalid node ID"); + // Ignore the returned value. + node.get_mut().replace_attributes(new); + } + /// Compares trees strictly. /// /// Returns `true` if the two trees are same. @@ -170,6 +214,8 @@ impl Tree { /// /// Note that this method compares tree data, not internal states of the /// objects. + #[inline] + #[must_use] pub fn strict_eq(&self, other: &Self) -> bool { self.root().strict_eq(&other.root()) } @@ -177,6 +223,8 @@ impl Tree { /// Pretty-print the tree for debugging purpose. /// /// Be careful, this output format may change in future. + #[inline] + #[must_use] pub fn debug_tree(&self) -> impl fmt::Debug + '_ { DebugTree { tree: self } } @@ -204,6 +252,7 @@ struct DebugTree<'a> { } impl fmt::Debug for DebugTree<'_> { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let v = DebugNodeHandle { node: self.tree.root(), @@ -245,3 +294,237 @@ impl fmt::Debug for DebugNodeHandleChildren<'_> { .finish() } } + +/// Event of depth-first traversal. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum DepthFirstTraversed { + /// Opening of a node. + Open(NodeId), + /// Closing of a node. + Close(NodeId), +} + +impl DepthFirstTraversed { + /// Returns the node ID. + #[inline] + #[must_use] + pub fn node_id(self) -> NodeId { + match self { + Self::Open(id) => id, + Self::Close(id) => id, + } + } + + /// Returns true if the event is node open. + #[inline] + #[must_use] + pub fn is_open(self) -> bool { + matches!(self, Self::Open(_)) + } + + /// Returns true if the event is node close. + #[inline] + #[must_use] + pub fn is_close(self) -> bool { + matches!(self, Self::Close(_)) + } + + /// Returns the opened node ID. + #[inline] + #[must_use] + pub fn node_id_open(self) -> Option { + match self { + Self::Open(id) => Some(id), + Self::Close(_) => None, + } + } + + /// Returns the closed node ID. + #[inline] + #[must_use] + pub fn node_id_close(self) -> Option { + match self { + Self::Open(_) => None, + Self::Close(id) => Some(id), + } + } + + /// Returns next (forward) event. + /// + /// Returns `None` for `Close(root_id)`. + #[must_use] + pub fn next(self, tree: &Tree) -> Option { + let next = match self { + Self::Open(current) => { + // Dive into the first child if available, or otherwise leave the node. + match current.to_handle(tree).first_child() { + Some(child) => Self::Open(child.node_id()), + None => Self::Close(current), + } + } + Self::Close(current) => { + // Dive into the next sibling if available, or leave the parent. + let node = current.to_handle(tree); + match node.next_sibling() { + Some(next_sib) => Self::Open(next_sib.node_id()), + None => Self::Close(node.parent()?.node_id()), + } + } + }; + Some(next) + } + + /// Returns previous (backward next) event. + /// + /// Note that this backward traversal returns `Clone` first, and `Open` + /// later for every node. + /// + /// Returns `None` for `Open(root_id)`. + #[must_use] + pub fn prev(self, tree: &Tree) -> Option { + let prev = match self { + Self::Close(current) => { + // Dive into the last child if available, or otherwise leave the node. + match current.to_handle(tree).last_child() { + Some(child) => Self::Close(child.node_id()), + None => Self::Open(current), + } + } + Self::Open(current) => { + // Dive into the previous sibling if available, or leave the parent. + let node = current.to_handle(tree); + match node.previous_sibling() { + Some(prev_sib) => Self::Close(prev_sib.node_id()), + None => Self::Open(node.parent()?.node_id()), + } + } + }; + Some(prev) + } +} + +/// A type to traverse a node and its descendants in depth-first order. +/// +/// This type has two cursors, forward cursor and backward cursor. +/// In the initial state, forward cursor points to the opening of the root node, +/// and the backward cursor points to the ending of the root node. +/// +/// Forward cursor advances forward, and backward cursor advances backward. +/// `next_forward` and `next_backward` methods returns the node ID the +/// corresponding cursor points to, and advances the cursor. +/// +/// When the forward cursor goes after the backward cursor, then all events are +/// considered emitted. +#[derive(Debug, Clone, Copy)] +pub struct DepthFirstTraverseSubtree { + /// Next (forward and backward) events to return. + cursors: Option<(DepthFirstTraversed, DepthFirstTraversed)>, +} + +impl DepthFirstTraverseSubtree { + /// Creates a new object. + #[inline] + #[must_use] + fn with_root_id(root: NodeId) -> Self { + Self { + cursors: Some(( + DepthFirstTraversed::Open(root), + DepthFirstTraversed::Close(root), + )), + } + } + + /// Returns the forward next traversal event and advances the forward cursor. + #[inline] + pub fn next_forward(&mut self, tree: &Tree) -> Option { + let (forward, backward) = self.cursors?; + if forward == backward { + self.cursors = None; + } else { + let next_of_next = forward + .next(tree) + .expect("`forward` should point before `backward`"); + self.cursors = Some((next_of_next, backward)); + } + Some(forward) + } + + /// Returns the backward next traversal event and advances the backward cursor. + #[inline] + pub fn next_backward(&mut self, tree: &Tree) -> Option { + let (forward, backward) = self.cursors?; + if forward == backward { + self.cursors = None; + } else { + let next_of_next = backward + .prev(tree) + .expect("`forward` should point before `backward`"); + self.cursors = Some((forward, next_of_next)); + } + Some(backward) + } + + /// Returns the forward next traversal event without advancing the cursor. + #[inline] + #[must_use] + pub fn peek_forward(&self) -> Option { + self.cursors.map(|(forward, _backward)| forward) + } + + /// Returns the backward next traversal event without advancing the cursor. + #[inline] + #[must_use] + pub fn peek_backward(&self) -> Option { + self.cursors.map(|(_forward, backward)| backward) + } + + /// Returns the forward next `Open` traversal event and advances the forward cursor. + /// + /// This makes it easy to forward-traverse the subtree in preorder. + pub fn next_open_forward(&mut self, tree: &Tree) -> Option { + loop { + let next = self.next_forward(tree)?; + if let DepthFirstTraversed::Open(id) = next { + return Some(id); + } + } + } + + /// Returns the forward next `Close` traversal event and advances the forward cursor. + /// + /// This makes it easy to forward-traverse the subtree in postorder. + pub fn next_close_forward(&mut self, tree: &Tree) -> Option { + loop { + let next = self.next_forward(tree)?; + if let DepthFirstTraversed::Close(id) = next { + return Some(id); + } + } + } + + /// Returns the backward next `Open` traversal event and advances the forward cursor. + /// + /// This makes it easy to backward-traverse the subtree in postorder. + #[must_use] + pub fn next_open_backward(&mut self, tree: &Tree) -> Option { + loop { + let next = self.next_backward(tree)?; + if let DepthFirstTraversed::Open(id) = next { + return Some(id); + } + } + } + + /// Returns the backward next `Close` traversal event and advances the forward cursor. + /// + /// This makes it easy to backward-traverse the subtree in preorder. + #[must_use] + pub fn next_close_backward(&mut self, tree: &Tree) -> Option { + loop { + let next = self.next_backward(tree)?; + if let DepthFirstTraversed::Close(id) = next { + return Some(id); + } + } + } +} diff --git a/src/tree/v7400/error.rs b/src/tree/v7400/error.rs index 52ebc2b..96a11e1 100644 --- a/src/tree/v7400/error.rs +++ b/src/tree/v7400/error.rs @@ -26,6 +26,7 @@ impl fmt::Display for LoadError { } impl error::Error for LoadError { + #[inline] fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { LoadError::Parser(e) => Some(e), @@ -35,6 +36,7 @@ impl error::Error for LoadError { } impl From for LoadError { + #[inline] fn from(e: ParserError) -> Self { LoadError::Parser(e) } diff --git a/src/tree/v7400/loader.rs b/src/tree/v7400/loader.rs index 0afbd94..1edfabb 100644 --- a/src/tree/v7400/loader.rs +++ b/src/tree/v7400/loader.rs @@ -26,6 +26,8 @@ pub struct Loader { impl Loader { /// Creates a new `Loader`. + #[inline] + #[must_use] pub fn new() -> Self { Self::default() } diff --git a/src/tree/v7400/node.rs b/src/tree/v7400/node.rs index 0a1c238..0066a6a 100644 --- a/src/tree/v7400/node.rs +++ b/src/tree/v7400/node.rs @@ -1,6 +1,6 @@ //! Node type. -use crate::tree::v7400::{NodeHandle, Tree}; +use crate::tree::v7400::{DepthFirstTraverseSubtree, NodeHandle, Tree}; pub(crate) use self::{data::NodeData, name::NodeNameSym}; @@ -14,11 +14,15 @@ pub struct NodeId(indextree::NodeId); impl NodeId { /// Creates a new `NodeId`. + #[inline] + #[must_use] pub(crate) fn new(id: indextree::NodeId) -> Self { NodeId(id) } /// Returns the raw node ID used by internal tree implementation. + #[inline] + #[must_use] pub(crate) fn raw(self) -> indextree::NodeId { self.0 } @@ -32,7 +36,16 @@ impl NodeId { /// Even if creation of an invalid node ID does not panic, subsequent /// operations through `NodeHandle` object may panic if the given node ID is /// not used in the given tree. + #[inline] + #[must_use] pub fn to_handle(self, tree: &Tree) -> NodeHandle<'_> { NodeHandle::new(tree, self) } + + /// Returns the helper object to traverse the subtree (the node itself and its descendant). + #[inline] + #[must_use] + pub fn traverse_depth_first(&self) -> DepthFirstTraverseSubtree { + DepthFirstTraverseSubtree::with_root_id(*self) + } } diff --git a/src/tree/v7400/node/data.rs b/src/tree/v7400/node/data.rs index 2251a1a..5b343c7 100644 --- a/src/tree/v7400/node/data.rs +++ b/src/tree/v7400/node/data.rs @@ -16,21 +16,40 @@ pub(crate) struct NodeData { impl NodeData { /// Returns the node name symbol. + #[inline] + #[must_use] pub(crate) fn name_sym(&self) -> NodeNameSym { self.name_sym } /// Returns the reference to the attributes. + #[inline] + #[must_use] pub(crate) fn attributes(&self) -> &[AttributeValue] { &self.attributes } /// Appends the given value to the attributes. + #[inline] pub(crate) fn append_attribute(&mut self, v: AttributeValue) { self.attributes.push(v) } + /// Appends the given value to the attributes. + #[inline] + pub(crate) fn get_attribute_mut(&mut self, i: usize) -> Option<&mut AttributeValue> { + self.attributes.get_mut(i) + } + + /// Replaces all attributes by the given one, and returns the old. + #[inline] + pub(crate) fn replace_attributes(&mut self, new: Vec) -> Vec { + std::mem::replace(&mut self.attributes, new) + } + /// Creates a new `NodeData`. + #[inline] + #[must_use] pub(crate) fn new(name_sym: NodeNameSym, attributes: Vec) -> Self { Self { name_sym, diff --git a/src/tree/v7400/node/handle.rs b/src/tree/v7400/node/handle.rs index 01bca11..c8158ae 100644 --- a/src/tree/v7400/node/handle.rs +++ b/src/tree/v7400/node/handle.rs @@ -26,6 +26,8 @@ impl<'a> NodeHandle<'a> { /// Even if `new()` does not panic, subsequent operations through /// `NodeHandle` object may panic if the given node ID is not used in the /// given tree. + #[inline] + #[must_use] pub(crate) fn new(tree: &'a Tree, node_id: NodeId) -> Self { assert!( tree.contains_node(node_id), @@ -37,31 +39,43 @@ impl<'a> NodeHandle<'a> { } /// Returns a reference to the tree. + #[inline] + #[must_use] pub fn tree(&self) -> &'a Tree { self.tree } /// Returns the node ID. + #[inline] + #[must_use] pub fn node_id(&self) -> NodeId { self.node_id } /// Returns the internally managed node data. + #[inline] + #[must_use] pub(crate) fn node(&self) -> &'a indextree::Node { self.tree.node(self.node_id) } /// Returns the node name symbol. + #[inline] + #[must_use] pub(crate) fn name_sym(&self) -> NodeNameSym { self.node().get().name_sym() } /// Returns the node name. + #[inline] + #[must_use] pub fn name(&self) -> &'a str { self.tree.resolve_node_name(self.name_sym()) } /// Returns the node attributes. + #[inline] + #[must_use] pub fn attributes(&self) -> &'a [AttributeValue] { self.node().get().attributes() } @@ -87,6 +101,7 @@ impl<'a> NodeHandle<'a> { } /// Returns the first child with the given name. + #[inline] #[must_use] pub fn first_child_by_name(&self, name: &str) -> Option { self.children_by_name(name).next() @@ -100,6 +115,8 @@ impl<'a> NodeHandle<'a> { /// /// Note that this method compares tree data, not internal states of the /// trees. + #[inline] + #[must_use] pub fn strict_eq(&self, other: &Self) -> bool { nodes_strict_eq(*self, *other) } @@ -121,6 +138,7 @@ macro_rules! impl_related_node_accessor { }; (@single, $(#[$meta:meta])* $accessor:ident;) => { $(#[$meta])* + #[must_use] pub fn $accessor(&self) -> Option> { self.node() .$accessor() @@ -143,6 +161,7 @@ impl_related_node_accessor! { } /// Compares nodes strictly. +#[must_use] fn nodes_strict_eq(left: NodeHandle<'_>, right: NodeHandle<'_>) -> bool { // Compare name. if left.name() != right.name() { @@ -199,6 +218,7 @@ impl<'a> Iterator for Children<'a> { impl std::iter::FusedIterator for Children<'_> {} impl<'a> fmt::Debug for Children<'a> { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Children").finish() } diff --git a/src/tree/v7400/node/name.rs b/src/tree/v7400/node/name.rs index be1725d..6e4c353 100644 --- a/src/tree/v7400/node/name.rs +++ b/src/tree/v7400/node/name.rs @@ -14,10 +14,12 @@ impl Symbol for NodeNameSym { /// As of writing this, string-interner 0.7.0 panics if the given value is /// greater than `u32::max_value() - 1`. /// See [`string_interner::Sym`] for detail. + #[inline] fn try_from_usize(v: usize) -> Option { SymbolU32::try_from_usize(v).map(Self) } + #[inline] fn to_usize(self) -> usize { self.0.to_usize() } diff --git a/src/writer/v7400/binary.rs b/src/writer/v7400/binary.rs index 7c100cb..f382308 100644 --- a/src/writer/v7400/binary.rs +++ b/src/writer/v7400/binary.rs @@ -145,16 +145,22 @@ impl Writer { } /// Returns a mutable reference to the sink. + #[inline] + #[must_use] fn sink(&mut self) -> &mut W { &mut self.sink } /// Returns a mutable reference to the node header of the current node. + #[inline] + #[must_use] fn current_node(&mut self) -> Option<&mut OpenNode> { self.open_nodes.last_mut() } /// Returns a mutable reference to the node header of the current node. + #[inline] + #[must_use] fn current_node_header(&mut self) -> Option<&mut NodeHeader> { self.current_node().map(|v| &mut v.header) } diff --git a/src/writer/v7400/binary/attributes.rs b/src/writer/v7400/binary/attributes.rs index e21e04f..e235232 100644 --- a/src/writer/v7400/binary/attributes.rs +++ b/src/writer/v7400/binary/attributes.rs @@ -28,6 +28,7 @@ pub(crate) trait IntoBytes: Sized { } impl IntoBytes for bool { + #[inline] fn call_with_le_bytes(self, f: impl FnOnce(&[u8]) -> R) -> R { let v = if self { b'Y' } else { b'T' }; f(&v.to_le_bytes()) @@ -35,30 +36,35 @@ impl IntoBytes for bool { } impl IntoBytes for i16 { + #[inline] fn call_with_le_bytes(self, f: impl FnOnce(&[u8]) -> R) -> R { f(&self.to_le_bytes()) } } impl IntoBytes for i32 { + #[inline] fn call_with_le_bytes(self, f: impl FnOnce(&[u8]) -> R) -> R { f(&self.to_le_bytes()) } } impl IntoBytes for i64 { + #[inline] fn call_with_le_bytes(self, f: impl FnOnce(&[u8]) -> R) -> R { f(&self.to_le_bytes()) } } impl IntoBytes for f32 { + #[inline] fn call_with_le_bytes(self, f: impl FnOnce(&[u8]) -> R) -> R { f(&self.to_bits().to_le_bytes()) } } impl IntoBytes for f64 { + #[inline] fn call_with_le_bytes(self, f: impl FnOnce(&[u8]) -> R) -> R { f(&self.to_bits().to_le_bytes()) } @@ -100,6 +106,7 @@ macro_rules! impl_arr_from_iter { }, )*) => {$( $(#[$meta])* + #[inline] pub fn $name( &mut self, encoding: impl Into>, @@ -114,6 +121,7 @@ macro_rules! impl_arr_from_iter { } $(#[$meta])* + #[inline] pub fn $name_from_result_iter( &mut self, encoding: impl Into>, @@ -134,11 +142,15 @@ macro_rules! impl_arr_from_iter { impl<'a, W: Write + Seek> AttributesWriter<'a, W> { /// Creates a new `AttributesWriter`. + #[inline] + #[must_use] pub(crate) fn new(writer: &'a mut Writer) -> Self { Self { writer } } /// Returns the inner writer. + #[inline] + #[must_use] pub(crate) fn sink(&mut self) -> &mut W { self.writer.sink() } @@ -184,6 +196,7 @@ impl<'a, W: Write + Seek> AttributesWriter<'a, W> { } /// Writes the given array attribute header. + #[inline] fn write_array_header(&mut self, header: &ArrayAttributeHeader) -> Result<()> { array::write_array_header(self.writer.sink(), header).map_err(Into::into) } diff --git a/src/writer/v7400/binary/error.rs b/src/writer/v7400/binary/error.rs index b06fb4a..c72917c 100644 --- a/src/writer/v7400/binary/error.rs +++ b/src/writer/v7400/binary/error.rs @@ -68,12 +68,14 @@ impl fmt::Display for Error { } impl From for Error { + #[inline] fn from(e: io::Error) -> Self { Error::Io(e) } } impl From for Error { + #[inline] fn from(e: CompressionError) -> Self { Error::Compression(e) } @@ -87,6 +89,7 @@ pub enum CompressionError { } impl error::Error for CompressionError { + #[inline] fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { CompressionError::Zlib(e) => Some(e), @@ -95,6 +98,7 @@ impl error::Error for CompressionError { } impl fmt::Display for CompressionError { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { CompressionError::Zlib(e) => write!(f, "Zlib compression error: {}", e), diff --git a/src/writer/v7400/binary/footer.rs b/src/writer/v7400/binary/footer.rs index 0ef0ff9..c691c8f 100644 --- a/src/writer/v7400/binary/footer.rs +++ b/src/writer/v7400/binary/footer.rs @@ -10,6 +10,7 @@ pub enum FbxFooterPaddingLength { } impl Default for FbxFooterPaddingLength { + #[inline] fn default() -> Self { FbxFooterPaddingLength::Default } @@ -46,6 +47,8 @@ pub struct FbxFooter<'a> { impl<'a> FbxFooter<'a> { /// Returns the first unknown field or default. + #[inline] + #[must_use] pub(crate) fn unknown1(&self) -> &'a [u8; 16] { /// Default value. const DEFAULT: [u8; 16] = [ @@ -56,6 +59,8 @@ impl<'a> FbxFooter<'a> { } /// Returns the second unknown field or default. + #[inline] + #[must_use] pub(crate) fn unknown2(&self) -> [u8; 4] { /// Default value. const DEFAULT: [u8; 4] = [0; 4]; @@ -63,6 +68,8 @@ impl<'a> FbxFooter<'a> { } /// Returns the third unknown field or default. + #[inline] + #[must_use] pub(crate) fn unknown3(&self) -> &'a [u8; 16] { /// Default value. const DEFAULT: [u8; 16] = [