diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..32736d9a --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,13 @@ +{ + "permissions": { + "allow": [ + "Bash(cargo test)", + "Bash(cargo test:*)", + "Bash(cargo clippy:*)", + "Bash(cargo fmt:*)", + "Bash(cargo:*)", + "Bash(gh pr view:*)" + ], + "deny": [] + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6c9155f8..1c0e900a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ Cargo.lock examples/debug-file.rs .env +.claude diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bae7eee..bb4e6547 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,12 @@ All notable changes to this project will be documented in this file. ### Code improvements +* optimized BytesMut buffer allocation patterns for better memory efficiency + * replaced `BytesMut::with_capacity() + resize()` with `BytesMut::zeroed()` for cleaner initialization + * added capacity pre-allocation in ASN encoding to avoid reallocations + * replaced unnecessary BytesMut allocations with direct slice references in MRT header parsing + * added capacity pre-allocation in MRT record encoding for optimal buffer sizing + * fixed non-canonical PartialOrd implementation for ASN type to follow Rust idioms * added BGP Flow-Spec parsing support following RFC 8955 and RFC 8956 * implemented complete Flow-Spec NLRI parsing for IPv4 and IPv6 Flow Specification rules * added support for all Flow-Spec component types (destination/source prefix, protocol, ports, ICMP, TCP flags, packet length, DSCP, fragment, flow label) diff --git a/src/models/network/asn.rs b/src/models/network/asn.rs index 0c20cff6..a53dd560 100644 --- a/src/models/network/asn.rs +++ b/src/models/network/asn.rs @@ -52,7 +52,7 @@ impl PartialEq for Asn { impl PartialOrd for Asn { fn partial_cmp(&self, other: &Self) -> Option { - Some(self.asn.cmp(&other.asn)) + Some(self.cmp(other)) } } @@ -278,7 +278,7 @@ impl FromStr for Asn { #[cfg(feature = "parser")] impl Asn { pub fn encode(&self) -> Bytes { - let mut bytes = BytesMut::new(); + let mut bytes = BytesMut::with_capacity(if self.four_byte { 4 } else { 2 }); match self.four_byte { true => bytes.put_u32(self.asn), false => bytes.put_u16(self.asn as u16), diff --git a/src/parser/mrt/mrt_header.rs b/src/parser/mrt/mrt_header.rs index 10282647..032fe349 100644 --- a/src/parser/mrt/mrt_header.rs +++ b/src/parser/mrt/mrt_header.rs @@ -42,7 +42,7 @@ use std::io::Read; pub fn parse_common_header(input: &mut T) -> Result { let mut raw_bytes = [0u8; 12]; input.read_exact(&mut raw_bytes)?; - let mut data = BytesMut::from(&raw_bytes[..]); + let mut data = &raw_bytes[..]; let timestamp = data.get_u32(); let entry_type_raw = data.get_u16(); @@ -56,7 +56,7 @@ pub fn parse_common_header(input: &mut T) -> Result None, }; diff --git a/src/parser/mrt/mrt_record.rs b/src/parser/mrt/mrt_record.rs index 94d3cd45..70311d6c 100644 --- a/src/parser/mrt/mrt_record.rs +++ b/src/parser/mrt/mrt_record.rs @@ -31,8 +31,7 @@ pub fn parse_mrt_record(input: &mut impl Read) -> Result Bytes { - let mut bytes = BytesMut::new(); let message_bytes = self.message.encode(self.common_header.entry_subtype); let mut new_header = self.common_header; if message_bytes.len() < new_header.length as usize { @@ -146,6 +144,7 @@ impl MrtRecord { // assert!(self.message == parsed_body); // // debug ends + let mut bytes = BytesMut::with_capacity(header_bytes.len() + message_bytes.len()); bytes.put_slice(&header_bytes); bytes.put_slice(&message_bytes); bytes.freeze()