Implement 'Default' for 'vec::IntoIter'; Mark 'String::is_char_boundary' with 'const'; Update lints; Clean up code; Bump MSRV to '1.86' for 'oct'; Bump Rust edition to '2024' for 'oct' and 'oct-macros' (and 'oct-benchmarks'); Fix '<vec::IntoIter as Iterator>::nth' not considering the current position; Optimise 'Iterator', 'DoubleEndedIterator', and 'ExactSizeIterator' implementations for 'vec::IntoIter'; Fix '<vec::IntoIter as Iterator>::size_hint' unsafely underflowing the size; Fix '<vec::IntoIter as Iterator>::nth' allowing out-of-bounds reads; Fix bounds on 'Arc' include in '/oct/src/decode/decode/mod.rs'; Implement 'PartialEq<Cow<str>>' for 'String'; Bring back 'vec' macro; Update syntax for 'string' macro; Unmark 'vec::IntoIter::{as_slice, as_mut_slice}' with 'const'; Optimise 'PartialEq', 'Eq', and 'PartialOrd' implementations; Rewrite 'Clone' implementations for 'Vec' and 'vec::IntoIter'; Update tests; Unimplement 'PartialEq<&mut [u8]>' for 'Slot'; Rewrite 'Vec::into_boxed_slice'; Rename 'Vec::into_alloc_vec' to 'into_vec';
This commit is contained in:
parent
c19051dc1c
commit
50be4ca4bb
28 changed files with 810 additions and 269 deletions
24
CHANGELOG.md
24
CHANGELOG.md
|
@ -3,6 +3,30 @@
|
|||
This is the changelog of [Oct](https://crates.io/crates/oct/).
|
||||
See `README.md` for more information.
|
||||
|
||||
## 0.19.0
|
||||
|
||||
* Implement `Default` for `vec::IntoIter`
|
||||
* Mark `String::is_char_boundary` with `const`
|
||||
* Update lints
|
||||
* Clean up code
|
||||
* Bump MSRV to `1.86` for `oct`
|
||||
* Bump Rust edition to `2024` for `oct` and `oct-macros` (and `oct-benchmarks`)
|
||||
* Fix `<vec::IntoIter as Iterator>::nth` not considering the current position
|
||||
* Optimise `Iterator`, `DoubleEndedIterator`, and `ExactSizeIterator` implementations for `vec::IntoIter`
|
||||
* Fix `<vec::IntoIter as Iterator>::size_hint` unsafely underflowing the size
|
||||
* Fix `<vec::IntoIter as Iterator>::nth` allowing out-of-bounds reads
|
||||
* Fix bounds on `Arc` include in `/oct/src/decode/decode/mod.rs`
|
||||
* Implement `PartialEq<Cow<str>>` for `String`
|
||||
* Bring back `vec` macro
|
||||
* Update syntax for `string` macro
|
||||
* Unmark `vec::IntoIter::{as_slice, as_mut_slice}` with `const`
|
||||
* Optimise `PartialEq`, `Eq`, and `PartialOrd` implementations
|
||||
* Rewrite `Clone` implementations for `Vec` and `vec::IntoIter`
|
||||
* Update tests
|
||||
* Unimplement `PartialEq<&mut [u8]>` for `Slot`
|
||||
* Rewrite `Vec::into_boxed_slice`
|
||||
* Rename `Vec::into_alloc_vec` to `into_vec`
|
||||
|
||||
## 0.18.0
|
||||
|
||||
* Clean up code
|
||||
|
|
16
Cargo.toml
16
Cargo.toml
|
@ -3,7 +3,7 @@ members = ["oct", "oct-benchmarks", "oct-macros"]
|
|||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.18.0"
|
||||
version = "0.19.0"
|
||||
authors = ["Gabriel Bjørnager Jensen"]
|
||||
readme = "README.md"
|
||||
repository = "https://gitlab.com/bjoernager/oct/"
|
||||
|
@ -34,6 +34,7 @@ cloned_instead_of_copied = "warn"
|
|||
collection_is_never_read = "warn"
|
||||
dbg_macro = "warn"
|
||||
debug_assert_with_mut_call = "warn"
|
||||
default_constructed_unit_structs = "forbid"
|
||||
deref_by_slicing = "warn"
|
||||
derive_partial_eq_without_eq = "warn"
|
||||
derived_hash_with_manual_eq = "forbid"
|
||||
|
@ -60,6 +61,7 @@ from_iter_instead_of_collect = "warn"
|
|||
future_not_send = "forbid"
|
||||
if_not_else = "warn"
|
||||
if_then_some_else_none = "warn"
|
||||
ignored_unit_patterns = "forbid"
|
||||
impl_trait_in_params = "warn"
|
||||
implicit_clone = "warn"
|
||||
imprecise_flops = "forbid"
|
||||
|
@ -68,6 +70,7 @@ index_refutable_slice = "warn"
|
|||
inefficient_to_string = "warn"
|
||||
infinite_loop = "forbid"
|
||||
into_iter_without_iter = "warn"
|
||||
invalid_atomic_ordering = "forbid"
|
||||
invalid_upcast_comparisons = "warn"
|
||||
iter_filter_is_ok = "warn"
|
||||
iter_filter_is_some = "warn"
|
||||
|
@ -76,6 +79,7 @@ iter_on_empty_collections = "warn"
|
|||
iter_on_single_items = "warn"
|
||||
iter_with_drain = "warn"
|
||||
iter_without_into_iter = "warn"
|
||||
let_unit_value = "forbid"
|
||||
macro_use_imports = "warn"
|
||||
manual_assert = "warn"
|
||||
manual_c_str_literals = "warn"
|
||||
|
@ -92,6 +96,7 @@ mismatching_type_param_order = "warn"
|
|||
missing_errors_doc = "forbid"
|
||||
missing_transmute_annotations = "forbid"
|
||||
mixed_read_write_in_expression = "forbid"
|
||||
must_use_unit = "forbid"
|
||||
mut_mut = "warn"
|
||||
mutex_atomic = "forbid"
|
||||
mutex_integer = "forbid"
|
||||
|
@ -107,11 +112,11 @@ non_ascii_literal = "forbid"
|
|||
nonstandard_macro_braces = "forbid"
|
||||
option_as_ref_cloned = "warn"
|
||||
option_if_let_else = "warn"
|
||||
option_map_unit_fn = "forbid"
|
||||
option_option = "warn"
|
||||
or_fun_call = "forbid"
|
||||
path_buf_push_overwrite = "warn"
|
||||
pattern_type_mismatch = "forbid"
|
||||
ptr_as_ptr = "forbid"
|
||||
ptr_cast_constness = "forbid"
|
||||
pub_underscore_fields = "forbid"
|
||||
range_plus_one = "warn"
|
||||
|
@ -126,6 +131,8 @@ ref_as_ptr = "forbid"
|
|||
ref_binding_to_reference = "warn"
|
||||
ref_option_ref = "warn"
|
||||
rest_pat_in_fully_bound_structs = "warn"
|
||||
result_map_unit_fn = "forbid"
|
||||
result_unit_err = "forbid"
|
||||
return_self_not_must_use = "forbid"
|
||||
same_functions_in_if_condition = "warn"
|
||||
same_name_method = "forbid"
|
||||
|
@ -146,6 +153,10 @@ transmute_ptr_to_ptr = "forbid"
|
|||
type_repetition_in_bounds = "forbid"
|
||||
uninhabited_references = "forbid"
|
||||
uninlined_format_args = "forbid"
|
||||
unit_arg = "forbid"
|
||||
unit_cmp = "forbid"
|
||||
unit_hash = "forbid"
|
||||
unit_return_expecting_ord = "forbid"
|
||||
unnecessary_box_returns = "forbid"
|
||||
unnecessary_join = "warn"
|
||||
unnecessary_self_imports = "forbid"
|
||||
|
@ -155,6 +166,7 @@ unnested_or_patterns = "warn"
|
|||
unused_async = "warn"
|
||||
unused_peekable = "warn"
|
||||
unused_rounding = "warn"
|
||||
unused_unit = "forbid"
|
||||
use_self = "forbid"
|
||||
used_underscore_binding = "warn"
|
||||
useless_let_if_seq = "warn"
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
avoid-breaking-exported-api = false
|
||||
allow-private-module-inception = true
|
||||
avoid-breaking-exported-api = false
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
[package]
|
||||
name = "oct-benchmarks"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
description = "Oct benchmarks."
|
||||
license = "MIT"
|
||||
|
||||
|
@ -32,7 +32,7 @@ readme.workspace = true
|
|||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
oct = { path = "../oct", version = "0.18", features = ["proc-macro"]}
|
||||
oct = { path = "../oct", version = "0.19", features = ["proc-macro"]}
|
||||
|
||||
bincode = "1.3.0"
|
||||
rand = "0.8.0"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
[package]
|
||||
name = "oct-macros"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
description = "Octonary transcoder. Procedural macros."
|
||||
documentation = "https://docs.rs/oct-macros/"
|
||||
homepage = "https://crates.io/crates/oct-macros/"
|
||||
|
|
|
@ -47,7 +47,7 @@ where
|
|||
enum_body(data, repr)
|
||||
}
|
||||
|
||||
Data::Union(..) => panic!("unions cannot derive `{trait_name}`"),
|
||||
Data::Union(..) => panic!("untagged unions cannot derive `{trait_name}`"),
|
||||
};
|
||||
|
||||
let generic_params = &input.generics.params;
|
||||
|
@ -64,4 +64,4 @@ where
|
|||
};
|
||||
|
||||
output
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
[package]
|
||||
name = "oct"
|
||||
edition = "2021"
|
||||
rust-version = "1.83"
|
||||
edition = "2024"
|
||||
rust-version = "1.86"
|
||||
description = "Octonary transcoder."
|
||||
documentation = "https://docs.rs/oct/"
|
||||
homepage = "https://crates.io/crates/oct/"
|
||||
|
@ -25,6 +25,9 @@ categories.workspace = true
|
|||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[dependencies]
|
||||
oct-macros = { path = "../oct-macros", version = "0.19", optional = true}
|
||||
|
||||
[features]
|
||||
default = ["alloc", "proc-macro", "std"]
|
||||
|
||||
|
@ -35,8 +38,5 @@ std = ["alloc"]
|
|||
f128 = []
|
||||
f16 = []
|
||||
|
||||
[dependencies]
|
||||
oct-macros = { path = "../oct-macros", version = "0.18", optional = true}
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -52,9 +52,11 @@ use {
|
|||
alloc::collections::{BinaryHeap, LinkedList},
|
||||
alloc::ffi::CString,
|
||||
alloc::rc::Rc,
|
||||
alloc::sync::Arc,
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
|
||||
use alloc::sync::Arc;
|
||||
|
||||
#[cfg(any(feature = "f128", feature = "f16"))]
|
||||
use crate::oct::encode::SizedEncode;
|
||||
|
||||
|
@ -130,7 +132,7 @@ impl<T: Decode, const N: usize> Decode for [T; N] {
|
|||
// about it from this point on. `transmute` cannot
|
||||
// be used here, and `transmute_unchecked` is re-
|
||||
// served for the greedy rustc devs. >:(
|
||||
let this = unsafe { buf.as_ptr().cast::<[T; N]>().read() };
|
||||
let this = unsafe { (buf.as_ptr() as *const [T; N]).read() };
|
||||
Ok(this)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -197,20 +197,38 @@ impl Eq for Input<'_> { }
|
|||
impl PartialEq for Input<'_> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_slice() == other.as_slice()
|
||||
*self.as_slice() == *other.as_slice()
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &Self) -> bool {
|
||||
*self.as_slice() != *other.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<[u8]> for Input<'_> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &[u8]) -> bool {
|
||||
self.as_slice() == other
|
||||
*self.as_slice() == *other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &[u8]) -> bool {
|
||||
*self.as_slice() != *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&[u8]> for Input<'_> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &&[u8]) -> bool {
|
||||
self.as_slice() == *other
|
||||
*self.as_slice() == **other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &&[u8]) -> bool {
|
||||
*self.as_slice() != **other
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,11 +32,13 @@
|
|||
//! assert_eq!(<(u8, u8)>::decode(&mut stream).unwrap(), (0x54, 0x45));
|
||||
//! ```
|
||||
|
||||
use crate::use_mod;
|
||||
mod decode;
|
||||
mod decode_borrowed;
|
||||
mod input;
|
||||
|
||||
use_mod!(pub decode);
|
||||
use_mod!(pub decode_borrowed);
|
||||
use_mod!(pub input);
|
||||
pub use decode::Decode;
|
||||
pub use decode_borrowed::DecodeBorrowed;
|
||||
pub use input::Input;
|
||||
|
||||
/// Implements [`Decode`] for the provided type.
|
||||
///
|
||||
|
|
|
@ -52,8 +52,6 @@ use {
|
|||
alloc::boxed::Box,
|
||||
alloc::collections::{BinaryHeap, LinkedList},
|
||||
alloc::ffi::CString,
|
||||
alloc::string::String,
|
||||
alloc::vec::Vec,
|
||||
alloc::rc::Rc,
|
||||
};
|
||||
|
||||
|
@ -237,17 +235,17 @@ impl<T: Encode> Encode for Bound<T> {
|
|||
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
|
||||
match *self {
|
||||
Self::Included(ref bound) => {
|
||||
let Ok(_) = 0x0u8.encode(output);
|
||||
let Ok(()) = 0x0u8.encode(output);
|
||||
bound.encode(output).map_err(EnumEncodeError::BadField)?;
|
||||
}
|
||||
|
||||
Self::Excluded(ref bound) => {
|
||||
let Ok(_) = 0x1u8.encode(output);
|
||||
let Ok(()) = 0x1u8.encode(output);
|
||||
bound.encode(output).map_err(EnumEncodeError::BadField)?;
|
||||
}
|
||||
|
||||
Self::Unbounded => {
|
||||
let Ok(_) = 0x2u8.encode(output);
|
||||
let Ok(()) = 0x2u8.encode(output);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,7 +479,7 @@ impl Encode for isize {
|
|||
let value = i16::try_from(*self)
|
||||
.map_err(|_| IsizeEncodeError(*self))?;
|
||||
|
||||
let Ok(_) = value.encode(output);
|
||||
let Ok(()) = value.encode(output);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -747,13 +745,13 @@ where
|
|||
|
||||
match *self {
|
||||
Ok(ref v) => {
|
||||
let Ok(_) = false.encode(output);
|
||||
let Ok(()) = false.encode(output);
|
||||
|
||||
v.encode(output)?;
|
||||
}
|
||||
|
||||
Err(ref e) => {
|
||||
let Ok(_) = true.encode(output);
|
||||
let Ok(()) = true.encode(output);
|
||||
|
||||
e.encode(output).map_err(Into::into)?;
|
||||
}
|
||||
|
@ -797,13 +795,13 @@ impl Encode for SocketAddr {
|
|||
|
||||
match *self {
|
||||
Self::V4(ref addr) => {
|
||||
let Ok(_) = 0x4u8.encode(output);
|
||||
let Ok(_) = addr.encode(output);
|
||||
let Ok(()) = 0x4u8.encode(output);
|
||||
let Ok(()) = addr.encode(output);
|
||||
}
|
||||
|
||||
Self::V6(ref addr) => {
|
||||
let Ok(_) = 0x6u8.encode(output);
|
||||
let Ok(_) = addr.encode(output);
|
||||
let Ok(()) = 0x6u8.encode(output);
|
||||
let Ok(()) = addr.encode(output);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -851,7 +849,7 @@ impl Encode for str {
|
|||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
|
||||
impl Encode for String {
|
||||
impl Encode for alloc::string::String {
|
||||
type Error = <str as Encode>::Error;
|
||||
|
||||
/// See [`prim@str`].
|
||||
|
@ -929,14 +927,14 @@ impl Encode for usize {
|
|||
let value = u16::try_from(*self)
|
||||
.map_err(|_| UsizeEncodeError(*self))?;
|
||||
|
||||
let Ok(_) = value.encode(output);
|
||||
let Ok(()) = value.encode(output);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
|
||||
impl<T: Encode> Encode for Vec<T> {
|
||||
impl<T: Encode> Encode for alloc::vec::Vec<T> {
|
||||
type Error = <[T] as Encode>::Error;
|
||||
|
||||
#[inline(always)]
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
use core::time::Duration;
|
||||
use oct::encode::{Encode, SizedEncode};
|
||||
use oct::error::UsizeEncodeError;
|
||||
use oct::string::String as OctString;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
macro_rules! test {
|
||||
|
@ -21,7 +20,7 @@ macro_rules! test {
|
|||
)*
|
||||
} => {{
|
||||
$($({
|
||||
let mut buf = ::std::vec![0x00; <$ty as ::oct::encode::SizedEncode>::MAX_ENCODED_SIZE];
|
||||
let mut buf = ::std::vec![0x00; 0x100];
|
||||
|
||||
let mut output = ::oct::encode::Output::new(&mut buf);
|
||||
|
||||
|
@ -75,12 +74,12 @@ fn test_encode() {
|
|||
]),
|
||||
}
|
||||
|
||||
OctString<0x1> {
|
||||
OctString::new("A").unwrap() => Ok(&[0x01, 0x00, 0x41]),
|
||||
str {
|
||||
"A" => Ok(&[0x01, 0x00, 0x41]),
|
||||
}
|
||||
|
||||
OctString<0xA> {
|
||||
OctString::new("l\u{00F8}gma\u{00F0}ur").unwrap() => Ok(&[
|
||||
str {
|
||||
"l\u{00F8}gma\u{00F0}ur" => Ok(&[
|
||||
0x0A, 0x00, 0x6C, 0xC3, 0xB8, 0x67, 0x6D, 0x61,
|
||||
0xC3, 0xB0, 0x75, 0x72,
|
||||
])
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
//! let mut stream = Output::new(&mut buf);
|
||||
//!
|
||||
//! // Note: For serialising multiple characters, the
|
||||
//! // `alloc::string::String` and `oct::str::
|
||||
//! // String` types are usually preferred.
|
||||
//! // `String` and `oct::str::String` types are usual-
|
||||
//! // ly preferred.
|
||||
//!
|
||||
//! 'ل'.encode(&mut stream).unwrap();
|
||||
//! 'ا'.encode(&mut stream).unwrap();
|
||||
|
@ -48,11 +48,13 @@
|
|||
//!
|
||||
//! If the encoded type additionally implements [`SizedEncode`], then the maximum size of any encoding is guaranteed with the [`MAX_ENCODED_SIZE`](SizedEncode::MAX_ENCODED_SIZE) constant.
|
||||
|
||||
use crate::use_mod;
|
||||
mod encode;
|
||||
mod output;
|
||||
mod sized_encode;
|
||||
|
||||
use_mod!(pub encode);
|
||||
use_mod!(pub output);
|
||||
use_mod!(pub sized_encode);
|
||||
pub use encode::Encode;
|
||||
pub use output::Output;
|
||||
pub use sized_encode::SizedEncode;
|
||||
|
||||
/// Implements [`Encode`] for the provided type.
|
||||
///
|
||||
|
|
|
@ -129,20 +129,38 @@ impl Eq for Output<'_> { }
|
|||
impl PartialEq for Output<'_> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_slice() == other.as_slice()
|
||||
*self.as_slice() == *other.as_slice()
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &Self) -> bool {
|
||||
*self.as_slice() != *other.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<[u8]> for Output<'_> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &[u8]) -> bool {
|
||||
self.as_slice() == other
|
||||
*self.as_slice() == *other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &[u8]) -> bool {
|
||||
*self.as_slice() != *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&[u8]> for Output<'_> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &&[u8]) -> bool {
|
||||
self.as_slice() == *other
|
||||
*self.as_slice() == **other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &&[u8]) -> bool {
|
||||
*self.as_slice() != **other
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ use {
|
|||
/// When using [`Encode`], the size of the resulting encoding cannot always be known beforehand.
|
||||
/// This trait defines an upper bound for these sizes.
|
||||
///
|
||||
/// Note that whilst *technically* having a size limit, [`Vec`](alloc::vec::Vec), [`String`](alloc::string::String), etc. do not implement this trait.
|
||||
/// Note that whilst *technically* having a size limit, [`alloc::vec::Vec`], [`alloc::string::String`], etc. do not implement this trait.
|
||||
/// The general rule is that the size limit must be a substantial part of a type's design to constitute implementing this trait.
|
||||
///
|
||||
/// Also note that -- in practice -- this trait is **not** strictly enforceable.
|
||||
|
|
|
@ -11,25 +11,44 @@
|
|||
//! This module defines the error types used by Oct.
|
||||
//! All of these types define (at least conditionally) the [`Error`](core::error::Error) trait.
|
||||
|
||||
use crate::use_mod;
|
||||
|
||||
use_mod!(pub char_decode_error);
|
||||
use_mod!(pub collection_decode_error);
|
||||
use_mod!(pub collection_encode_error);
|
||||
use_mod!(pub enum_decode_error);
|
||||
use_mod!(pub enum_encode_error);
|
||||
use_mod!(pub generic_decode_error);
|
||||
use_mod!(pub generic_encode_error);
|
||||
use_mod!(pub input_error);
|
||||
use_mod!(pub isize_encode_error);
|
||||
use_mod!(pub item_decode_error);
|
||||
use_mod!(pub item_encode_error);
|
||||
use_mod!(pub length_error);
|
||||
use_mod!(pub non_zero_decode_error);
|
||||
use_mod!(pub output_error);
|
||||
use_mod!(pub ref_cell_encode_error);
|
||||
use_mod!(pub usize_encode_error);
|
||||
use_mod!(pub utf8_error);
|
||||
mod char_decode_error;
|
||||
mod collection_decode_error;
|
||||
mod collection_encode_error;
|
||||
mod enum_decode_error;
|
||||
mod enum_encode_error;
|
||||
mod generic_decode_error;
|
||||
mod generic_encode_error;
|
||||
mod input_error;
|
||||
mod isize_encode_error;
|
||||
mod item_decode_error;
|
||||
mod item_encode_error;
|
||||
mod length_error;
|
||||
mod non_zero_decode_error;
|
||||
mod output_error;
|
||||
mod ref_cell_encode_error;
|
||||
mod usize_encode_error;
|
||||
mod utf8_error;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use_mod!(pub system_time_decode_error);
|
||||
mod system_time_decode_error;
|
||||
|
||||
pub use char_decode_error::CharDecodeError;
|
||||
pub use collection_decode_error::CollectionDecodeError;
|
||||
pub use collection_encode_error::CollectionEncodeError;
|
||||
pub use enum_decode_error::EnumDecodeError;
|
||||
pub use enum_encode_error::EnumEncodeError;
|
||||
pub use generic_decode_error::GenericDecodeError;
|
||||
pub use generic_encode_error::GenericEncodeError;
|
||||
pub use input_error::InputError;
|
||||
pub use isize_encode_error::IsizeEncodeError;
|
||||
pub use item_decode_error::ItemDecodeError;
|
||||
pub use item_encode_error::ItemEncodeError;
|
||||
pub use length_error::LengthError;
|
||||
pub use non_zero_decode_error::NonZeroDecodeError;
|
||||
pub use output_error::OutputError;
|
||||
pub use ref_cell_encode_error::RefCellEncodeError;
|
||||
pub use usize_encode_error::UsizeEncodeError;
|
||||
pub use utf8_error::Utf8Error;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use system_time_decode_error::SystemTimeDecodeError;
|
||||
|
|
|
@ -235,16 +235,8 @@ extern crate alloc;
|
|||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
/// Includes a module and imports it contents.
|
||||
///
|
||||
/// The provided visibility denotes the visibility of **all** imported items.
|
||||
macro_rules! use_mod {
|
||||
($vis:vis $name:ident$(,)?) => {
|
||||
mod $name;
|
||||
$vis use $name::*;
|
||||
};
|
||||
}
|
||||
pub(crate) use use_mod;
|
||||
mod prim_discriminant;
|
||||
mod prim_repr;
|
||||
|
||||
pub mod decode;
|
||||
pub mod encode;
|
||||
|
@ -255,24 +247,42 @@ pub mod vec;
|
|||
#[cfg(feature = "alloc")]
|
||||
pub mod slot;
|
||||
|
||||
use_mod!(pub prim_discriminant);
|
||||
use_mod!(pub prim_repr);
|
||||
pub use prim_discriminant::PrimDiscriminant;
|
||||
pub use prim_repr::PrimRepr;
|
||||
|
||||
pub(crate) use prim_repr::SealedPrimRepr;
|
||||
|
||||
/// Directly constructs a [`Vec`](crate::vec::Vec) object.
|
||||
///
|
||||
/// This macro tests at compile-time whether the provided data can fit into the inferred length.
|
||||
/// Compilation will fail if this is not the case.
|
||||
#[macro_export]
|
||||
macro_rules! vec {
|
||||
[$value:literal; $len:expr] => {{
|
||||
const { $crate::vec::__vec([$value; $len]) }
|
||||
}};
|
||||
|
||||
[$($value:expr),+ $(,)?] => {{
|
||||
const { $crate::vec::__vec([$($value,)*]) }
|
||||
}};
|
||||
|
||||
[] => {{
|
||||
const { $crate::vec::__vec([]) }
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
/// Directly constructs a [`String`](crate::string::String) object.
|
||||
///
|
||||
/// This macro tests at compile-time whether the string literal can fit into the specified (or inferred) length.
|
||||
/// This macro tests at compile-time whether the string literal can fit into the inferred length.
|
||||
/// Compilation will fail if this is not the case.
|
||||
#[macro_export]
|
||||
macro_rules! string {
|
||||
($s:expr, $len:expr) => {{
|
||||
const { $crate::string::__str::<$len>($s) }
|
||||
}};
|
||||
|
||||
($s:expr) => {{
|
||||
const { $crate::string::__str($s) }
|
||||
const { $crate::string::__string($s) }
|
||||
}};
|
||||
|
||||
() => {{
|
||||
const { $crate::string::__str("") }
|
||||
const { $crate::string::__string("") }
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ macro_rules! impl_prim_repr {
|
|||
($ty:ty => $variant:ident) => {
|
||||
impl ::oct::SealedPrimRepr for $ty { }
|
||||
|
||||
impl PrimRepr for $ty {
|
||||
impl ::oct::PrimRepr for $ty {
|
||||
#[inline(always)]
|
||||
fn into_prim_discriminant(self) -> ::oct::PrimDiscriminant {
|
||||
::oct::PrimDiscriminant::$variant(self)
|
||||
|
@ -49,4 +49,4 @@ impl_prim_repr!(i16 => I16);
|
|||
impl_prim_repr!(i32 => I32);
|
||||
impl_prim_repr!(i64 => I64);
|
||||
impl_prim_repr!(i128 => I128);
|
||||
impl_prim_repr!(isize => Isize);
|
||||
impl_prim_repr!(isize => Isize);
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
//!
|
||||
//! *See the [`Slot`] type for more information.*
|
||||
|
||||
use crate::use_mod;
|
||||
mod slot;
|
||||
|
||||
use_mod!(pub slot);
|
||||
pub use slot::Slot;
|
||||
|
|
|
@ -56,8 +56,8 @@ use core::slice::{self, SliceIndex};
|
|||
/// ```
|
||||
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
|
||||
pub struct Slot<T> {
|
||||
buf: Box<[u8]>,
|
||||
len: usize,
|
||||
buf: Box<[u8]>,
|
||||
|
||||
_ty: PhantomData<fn() -> T>,
|
||||
}
|
||||
|
@ -100,8 +100,8 @@ impl<T> Slot<T> {
|
|||
};
|
||||
|
||||
Self {
|
||||
buf,
|
||||
len,
|
||||
buf,
|
||||
|
||||
_ty: PhantomData,
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ impl<T: SizedEncode> Slot<T> {
|
|||
impl<T> AsMut<[u8]> for Slot<T> {
|
||||
#[inline(always)]
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
self.as_mut_slice()
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,7 +319,7 @@ impl<T> AsMut<[u8]> for Slot<T> {
|
|||
impl<T> AsRef<[u8]> for Slot<T> {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.as_slice()
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,7 +328,7 @@ impl<T> AsRef<[u8]> for Slot<T> {
|
|||
impl<T> Borrow<[u8]> for Slot<T> {
|
||||
#[inline(always)]
|
||||
fn borrow(&self) -> &[u8] {
|
||||
self.as_slice()
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,14 +337,14 @@ impl<T> Borrow<[u8]> for Slot<T> {
|
|||
impl<T> BorrowMut<[u8]> for Slot<T> {
|
||||
#[inline(always)]
|
||||
fn borrow_mut(&mut self) -> &mut [u8] {
|
||||
self.as_mut_slice()
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
|
||||
impl<T> Debug for Slot<T> {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{:?}", self.as_slice()) }
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{:?}", &**self) }
|
||||
}
|
||||
|
||||
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
|
||||
|
@ -379,7 +379,7 @@ impl<T, I: SliceIndex<[u8]>> Index<I> for Slot<T> {
|
|||
|
||||
#[inline(always)]
|
||||
fn index(&self, index: I) -> &Self::Output {
|
||||
self.get(index).unwrap()
|
||||
Index::index(&**self, index)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -387,7 +387,7 @@ impl<T, I: SliceIndex<[u8]>> Index<I> for Slot<T> {
|
|||
impl<T, I: SliceIndex<[u8]>> IndexMut<I> for Slot<T> {
|
||||
#[inline(always)]
|
||||
fn index_mut(&mut self, index: I) -> &mut Self::Output {
|
||||
self.get_mut(index).unwrap()
|
||||
IndexMut::index_mut(&mut **self, index)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -395,7 +395,13 @@ impl<T, I: SliceIndex<[u8]>> IndexMut<I> for Slot<T> {
|
|||
impl<T> PartialEq<[u8]> for Slot<T> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &[u8]) -> bool {
|
||||
self.as_slice() == other
|
||||
**self == *other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &[u8]) -> bool {
|
||||
**self != *other
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,14 +409,12 @@ impl<T> PartialEq<[u8]> for Slot<T> {
|
|||
impl<T> PartialEq<&[u8]> for Slot<T> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &&[u8]) -> bool {
|
||||
self.as_slice() == *other
|
||||
**self == **other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
|
||||
impl<T> PartialEq<&mut [u8]> for Slot<T> {
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &&mut [u8]) -> bool {
|
||||
self.as_slice() == *other
|
||||
fn ne(&self, other: &&[u8]) -> bool {
|
||||
**self != **other
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
|
||||
//! String container.
|
||||
|
||||
use crate::use_mod;
|
||||
mod string;
|
||||
|
||||
use_mod!(pub string);
|
||||
pub use string::{__string, String};
|
||||
|
|
|
@ -25,7 +25,10 @@ use core::slice::{self, SliceIndex};
|
|||
use core::str::{self, FromStr};
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::boxed::Box;
|
||||
use {
|
||||
alloc::borrow::Cow,
|
||||
alloc::boxed::Box,
|
||||
};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use {
|
||||
|
@ -94,7 +97,7 @@ impl<const N: usize> String<N> {
|
|||
|
||||
unsafe {
|
||||
let src = s.as_ptr();
|
||||
let dst = buf.as_mut_ptr().cast();
|
||||
let dst = buf.as_mut_ptr();
|
||||
|
||||
copy_nonoverlapping(src, dst, len);
|
||||
}
|
||||
|
@ -122,7 +125,7 @@ impl<const N: usize> String<N> {
|
|||
|
||||
unsafe {
|
||||
let src = s.as_ptr();
|
||||
let dst = buf.as_mut_ptr().cast();
|
||||
let dst = buf.as_mut_ptr();
|
||||
|
||||
copy_nonoverlapping(src, dst, len);
|
||||
}
|
||||
|
@ -181,7 +184,7 @@ impl<const N: usize> String<N> {
|
|||
// SAFETY: We can safely transmute here as
|
||||
// `MaybeUninit<u8>` is transparent to `u8` and
|
||||
// we have initialised the remaining bytes.
|
||||
let buf = unsafe { buf.as_ptr().cast::<[u8; N]>().read() };
|
||||
let buf = unsafe { (buf.as_ptr() as *const [u8; N]).read() };
|
||||
|
||||
// SAFETY: `Vec::into_raw_parts` guarantees that
|
||||
// the returned length is not greater than `N`.
|
||||
|
@ -228,10 +231,7 @@ impl<const N: usize> String<N> {
|
|||
/// In this case, character is defined as a set of one to four UTF-8 octets that represent a Unicode code point (specifically a Unicode scalar).
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn is_char_boundary(&self, index: usize) -> bool {
|
||||
// TODO: Mark with `const` when `const_is_char_
|
||||
// boundary` lands.
|
||||
|
||||
pub const fn is_char_boundary(&self, index: usize) -> bool {
|
||||
self.as_str().is_char_boundary(index)
|
||||
}
|
||||
|
||||
|
@ -329,7 +329,7 @@ impl<const N: usize> String<N> {
|
|||
let (buf, len) = self.into_raw_parts();
|
||||
|
||||
// SAFETY: `MaybeUninit<u8>` is transparent to `u8`.
|
||||
let buf = unsafe { (&raw const buf).cast::<[MaybeUninit<u8>; N]>().read() };
|
||||
let buf = unsafe { (&raw const buf as *const [MaybeUninit<u8>; N]).read() };
|
||||
|
||||
unsafe { Vec::from_raw_parts(buf, len) }
|
||||
|
||||
|
@ -492,9 +492,9 @@ impl<const N: usize> FromIterator<char> for String<N> {
|
|||
if rem < req { break }
|
||||
|
||||
let start = len;
|
||||
let stop = start + req;
|
||||
let end = start + req;
|
||||
|
||||
c.encode_utf8(&mut buf[start..stop]);
|
||||
c.encode_utf8(&mut buf[start..end]);
|
||||
|
||||
len += req;
|
||||
}
|
||||
|
@ -542,28 +542,61 @@ impl<I: SliceIndex<str>, const N: usize> IndexMut<I> for String<N> {
|
|||
impl<const N: usize> Ord for String<N> {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.as_str().cmp(other.as_str())
|
||||
(**self).cmp(&**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize, const M: usize> PartialEq<String<M>> for String<N> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &String<M>) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
**self == **other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &String<M>) -> bool {
|
||||
**self != **other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
|
||||
impl<const N: usize> PartialEq<Cow<'_, str>> for String<N> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Cow<str>) -> bool {
|
||||
**self == **other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &Cow<str>) -> bool {
|
||||
**self != **other
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> PartialEq<str> for String<N> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
self.as_str() == other
|
||||
**self == *other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &str) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> PartialEq<&str> for String<N> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
self == *other
|
||||
**self == **other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &&str) -> bool {
|
||||
**self != **other
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -572,14 +605,40 @@ impl<const N: usize> PartialEq<&str> for String<N> {
|
|||
impl<const N: usize> PartialEq<alloc::string::String> for String<N> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &alloc::string::String) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
*self == **other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &alloc::string::String) -> bool {
|
||||
*self != **other
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize, const M: usize> PartialOrd<String<M>> for String<N> {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &String<M>) -> Option<Ordering> {
|
||||
self.as_str().partial_cmp(other.as_str())
|
||||
(**self).partial_cmp(other)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn lt(&self, other: &String<M>) -> bool {
|
||||
**self < **other
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn le(&self, other: &String<M>) -> bool {
|
||||
**self <= **other
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gt(&self, other: &String<M>) -> bool {
|
||||
**self > **other
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ge(&self, other: &String<M>) -> bool {
|
||||
**self >= **other
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -671,7 +730,7 @@ impl<const N: usize> PartialEq<String<N>> for alloc::string::String {
|
|||
#[inline(always)]
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub const fn __str<const N: usize>(s: &'static str) -> String<N> {
|
||||
pub const fn __string<const N: usize>(s: &'static str) -> String<N> {
|
||||
assert!(s.len() <= N, "cannot construct string from literal that is longer");
|
||||
|
||||
// SAFETY: `s` has been tested to not contain more
|
||||
|
|
|
@ -14,7 +14,7 @@ use oct::vec::Vec;
|
|||
|
||||
#[test]
|
||||
fn test_str_macro() {
|
||||
let s0: String<0x3> = string!("Oct", 0x3);
|
||||
let s0: String<0x3> = string!("Oct");
|
||||
let s1: String<0x3> = string!("Oct");
|
||||
|
||||
assert_eq!(s0, s1);
|
||||
|
@ -28,9 +28,9 @@ fn test_string() {
|
|||
|
||||
#[test]
|
||||
fn test_string_size() {
|
||||
let s0 = string!("Hello there!", 0x0C);
|
||||
let s1 = string!("MEIN_GRO\u{1E9E}_GOTT", 0x12);
|
||||
let s2 = string!("Hello", 0x05);
|
||||
let s0: String<0x0C> = string!("Hello there!");
|
||||
let s1: String<0x12> = string!("MEIN_GRO\u{1E9E}_GOTT");
|
||||
let s2: String<0x05> = string!("Hello");
|
||||
|
||||
assert_eq!(s0.partial_cmp(&s0), Some(Ordering::Equal));
|
||||
assert_eq!(s0.partial_cmp(&s1), Some(Ordering::Less));
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
use crate::vec::{clone_to_uninit_in_range, Vec};
|
||||
|
||||
use core::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator};
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ptr::drop_in_place;
|
||||
|
@ -16,50 +18,110 @@ use core::slice;
|
|||
|
||||
/// Owning iterator to a vector.
|
||||
///
|
||||
/// This type is exclusively used by the deconstruction of the [`Vec`](crate::vec::Vec) type.
|
||||
/// When just borrowing such vectors, the standard library's <code>core::slice::{[Iter](core::slice::Iter), [IterMut](core::slice::IterMut)}</code> types are used instead.
|
||||
/// This type is exclusively used by the deconstruction of the [`Vec`] type, as per <code>[IntoIterator]::[into_iter](IntoIterator::into_iter)</code>.
|
||||
#[must_use]
|
||||
pub struct IntoIter<T, const N: usize> {
|
||||
len: usize,
|
||||
/// The cursor position in the buffer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This field may not be greater than [`isize::MAX`].
|
||||
pos: usize,
|
||||
|
||||
/// The length; the count remaining of alive elements remaining in the buffer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This field may not be greater than [`isize::MAX`].
|
||||
len: usize,
|
||||
|
||||
/// The internal buffer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// We must **always** guarantee that all objects in the range `pos..pos + len` are initialised and alive.
|
||||
/// One may therefore assume that interpreting these objects as such is valid.
|
||||
buf: [MaybeUninit<T>; N],
|
||||
}
|
||||
|
||||
impl<T, const N: usize> IntoIter<T, N> {
|
||||
/// Constructs a new, size-constrained iterator.
|
||||
/// Constructs a new, owning iterator to a vector.
|
||||
#[inline(always)]
|
||||
#[track_caller]
|
||||
pub(super) const unsafe fn new(buf: [MaybeUninit<T>; N], len: usize) -> Self {
|
||||
debug_assert!(len <= N, "cannot construct iterator longer than its capacity");
|
||||
pub(super) fn new(v: Vec<T, N>) -> Self {
|
||||
let (buf, len) = v.into_raw_parts();
|
||||
|
||||
Self { len, pos: 0x0, buf }
|
||||
let pos = Default::default();
|
||||
|
||||
Self { pos, len, buf }
|
||||
}
|
||||
|
||||
/// Incremenets the cursor position by a specified amount.
|
||||
///
|
||||
/// The caller is responsible for dropping the skipped elements.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The iterator `self` may not contain less than `count` elements.
|
||||
#[inline(always)]
|
||||
#[track_caller]
|
||||
unsafe fn advance_by_unchecked(&mut self, count: usize) {
|
||||
debug_assert!(count <= self.len);
|
||||
|
||||
// SAFETY: The caller guarantees that at least
|
||||
// `count` element are remaining.
|
||||
self.len = unsafe { self.len.unchecked_sub(count) };
|
||||
|
||||
// SAFETY: It is not invalid for us to go one-past-
|
||||
// the-end or exceed `isize::MAX`; `len` guarantees
|
||||
// that this counter will not be used as a pointer
|
||||
// offset if this would happen.
|
||||
self.pos = unsafe { self.pos.unchecked_add(count) };
|
||||
}
|
||||
|
||||
/// Decrements the length counter by a specified amount.
|
||||
///
|
||||
/// The caller is responsible for dropping the skipped elements.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The iterator `self` may not contain less than `count` elements.
|
||||
#[inline(always)]
|
||||
#[track_caller]
|
||||
unsafe fn advance_back_by_unchecked(&mut self, count: usize) {
|
||||
debug_assert!(count <= self.len);
|
||||
|
||||
// SAFETY: The caller guarantees that at least
|
||||
// `count` element are remaining.
|
||||
self.len = unsafe { self.len.unchecked_sub(count) };
|
||||
}
|
||||
|
||||
/// Gets a slice of the remaining elements.
|
||||
#[inline(always)]
|
||||
pub const fn as_slice(&self) -> &[T] {
|
||||
unsafe {
|
||||
let ptr = self.buf
|
||||
.as_ptr()
|
||||
.add(self.pos)
|
||||
.cast();
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
let pos = self.pos;
|
||||
let len = self.len;
|
||||
|
||||
slice::from_raw_parts(ptr, self.len)
|
||||
}
|
||||
// SAFETY: `MaybeUninit<T>` is transparent to `T`.
|
||||
let base = self.buf.as_ptr() as *const T;
|
||||
|
||||
let ptr = unsafe { base.add(pos) };
|
||||
|
||||
unsafe { slice::from_raw_parts(ptr, len) }
|
||||
}
|
||||
|
||||
/// Gets a mutable slice of the remaining elements.
|
||||
#[inline(always)]
|
||||
pub const fn as_mut_slice(&mut self) -> &mut [T] {
|
||||
unsafe {
|
||||
let ptr = self.buf
|
||||
.as_mut_ptr()
|
||||
.add(self.pos)
|
||||
.cast();
|
||||
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
||||
let pos = self.pos;
|
||||
let len = self.len;
|
||||
|
||||
slice::from_raw_parts_mut(ptr, self.len)
|
||||
}
|
||||
// SAFETY: `MaybeUninit<T>` is transparent to `T`.
|
||||
let base = self.buf.as_mut_ptr() as *mut T;
|
||||
|
||||
let ptr = unsafe { base.add(pos) };
|
||||
|
||||
unsafe { slice::from_raw_parts_mut(ptr, len) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,39 +142,135 @@ impl<T, const N: usize> AsRef<[T]> for IntoIter<T, N> {
|
|||
impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
let mut buf = [const { MaybeUninit::<T>::uninit() }; N];
|
||||
let pos = self.pos;
|
||||
let len = self.len;
|
||||
let mut buf = [const { MaybeUninit::uninit() }; N];
|
||||
|
||||
let Self { pos, len, .. } = *self;
|
||||
// SAFETY: `MaybeUninit<T>` is transparent to `T`.
|
||||
let src = self.buf.as_ptr() as *const T;
|
||||
|
||||
let dst = buf.as_mut_ptr() as *mut T;
|
||||
|
||||
let start = pos;
|
||||
let stop = start + len;
|
||||
let end = pos + len;
|
||||
|
||||
for i in start..stop {
|
||||
unsafe {
|
||||
let item = (&raw const *self.buf.get_unchecked(i)).cast();
|
||||
// SAFETY: The range
|
||||
//
|
||||
// pos..pos + len
|
||||
//
|
||||
// defines in and of itself the bounds of valid
|
||||
// elements.
|
||||
unsafe { clone_to_uninit_in_range(src, dst, start..end) };
|
||||
|
||||
let value = Clone::clone(&*item);
|
||||
// SAFETY: The buffer has been initialised in the
|
||||
// provided range - which does not extend beyond
|
||||
// bounds.
|
||||
Self { pos, len, buf }
|
||||
}
|
||||
}
|
||||
|
||||
buf.get_unchecked_mut(i).write(value);
|
||||
}
|
||||
}
|
||||
|
||||
Self { len, pos, buf }
|
||||
impl<T, const N: usize> Default for IntoIter<T, N> {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
Vec::default().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
// Test whether the iterator is empty.
|
||||
|
||||
if self.len == 0x0 { return None };
|
||||
|
||||
// Take the next value.
|
||||
|
||||
// Get a pointer to the next item.
|
||||
|
||||
// SAFETY: `self.pos` is guaranteed to always be
|
||||
// within bounds. `self.pos + self.len` is guaran-
|
||||
// teed one-past-the-end index.
|
||||
let index = self.pos + self.len - 0x1;
|
||||
|
||||
let item = unsafe { self.buf.get_unchecked(index).assume_init_read() };
|
||||
// SAFETY: `MaybeUninit<T>` is transparent to `T`.
|
||||
let base = self.buf.as_ptr() as *const T;
|
||||
|
||||
self.len -= 0x1;
|
||||
let item = unsafe { base.add(index) };
|
||||
|
||||
Some(item)
|
||||
// Read the item value.
|
||||
|
||||
// SAFETY: We guarantee that all items in the range
|
||||
//
|
||||
// self.pos..self.pos + self.len
|
||||
//
|
||||
// are alive (and initialised).
|
||||
let value = unsafe { item.read() };
|
||||
|
||||
// Update counters, **not** including the position.
|
||||
|
||||
// SAFETY: We have tested that at least one element
|
||||
// remains.
|
||||
unsafe { self.advance_back_by_unchecked(0x1) };
|
||||
|
||||
Some(value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
|
||||
// Test whether the iterator is empty.
|
||||
|
||||
if n >= self.len { return None };
|
||||
|
||||
// SAFETY: We have tested that there are at least
|
||||
// `n + 1` elements left.
|
||||
|
||||
// Get the indeces of the involved items.
|
||||
|
||||
let end = self.pos + self.len;
|
||||
let index = end - n;
|
||||
let start = index + 0x1;
|
||||
|
||||
// SAFETY: `MaybeUninit<T>` is transparent to `T`.
|
||||
let base = self.buf.as_mut_ptr() as *mut T;
|
||||
|
||||
// Drop each skipped element in **reverse** order.
|
||||
|
||||
for i in (start..end).rev() {
|
||||
let item = unsafe { base.add(i) };
|
||||
|
||||
// SAFETY: We guarantee that all items in the range
|
||||
//
|
||||
// self.pos..self.pos + self.len
|
||||
//
|
||||
// are alive (and initialised).
|
||||
unsafe { drop_in_place(item) };
|
||||
}
|
||||
|
||||
// Read the final value.
|
||||
|
||||
let item = unsafe { base.add(index) };
|
||||
|
||||
// SAFETY: We guarantee that all items in the range
|
||||
//
|
||||
// self.pos..self.pos + self.len
|
||||
//
|
||||
// are alive (and initialised).
|
||||
let value = unsafe { item.read() };
|
||||
|
||||
// Update counters, **not** including the position.
|
||||
|
||||
// SAFETY: This cannot overflow as `n` has been
|
||||
// tested to be less than `self.len`, which itself
|
||||
// cannot be greater than `isize::MAX`.
|
||||
let count = unsafe { n.unchecked_add(0x1) };
|
||||
|
||||
// SAFETY: We have tested that there are at least
|
||||
// `count` elements left.
|
||||
unsafe { self.advance_back_by_unchecked(count) };
|
||||
|
||||
// Return the value.
|
||||
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,7 +279,7 @@ impl<T, const N: usize> Drop for IntoIter<T, N> {
|
|||
fn drop(&mut self) {
|
||||
// Drop every element that hasn't been consumed.
|
||||
|
||||
let remaining = &raw mut *self.as_mut_slice();
|
||||
let remaining = self.as_mut_slice();
|
||||
unsafe { drop_in_place(remaining) };
|
||||
|
||||
// We do not need to ensure that `self` is in a
|
||||
|
@ -129,7 +287,12 @@ impl<T, const N: usize> Drop for IntoIter<T, N> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> { }
|
||||
impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
|
||||
#[inline(always)]
|
||||
fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const N: usize> FusedIterator for IntoIter<T, N> { }
|
||||
|
||||
|
@ -138,50 +301,119 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
|
|||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// Test whether the iterator is empty.
|
||||
|
||||
if self.len == 0x0 { return None };
|
||||
|
||||
// Take the next value.
|
||||
|
||||
// Get a pointer to the next item.
|
||||
|
||||
// SAFETY: `self.pos` is guaranteed to always be
|
||||
// within bounds.
|
||||
let index = self.pos;
|
||||
|
||||
let item = unsafe { self.buf.get_unchecked(index).assume_init_read() };
|
||||
// SAFETY: `MaybeUninit<T>` is transparent to `T`.
|
||||
let base = self.buf.as_ptr() as *const T;
|
||||
|
||||
self.len -= 0x1;
|
||||
self.pos += 0x1;
|
||||
let item = unsafe { base.add(index) };
|
||||
|
||||
Some(item)
|
||||
// Read the item value.
|
||||
|
||||
// SAFETY: We guarantee that all items in the range
|
||||
//
|
||||
// self.pos..self.pos + self.len
|
||||
//
|
||||
// are alive (and initialised).
|
||||
let value = unsafe { item.read() };
|
||||
|
||||
// Update counters.
|
||||
|
||||
// SAFETY: We have tested that at least one element
|
||||
// remains.
|
||||
unsafe { self.advance_by_unchecked(0x1) };
|
||||
|
||||
// Return the item value.
|
||||
|
||||
Some(value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth(&mut self, index: usize) -> Option<Self::Item> {
|
||||
if index > self.len { return None };
|
||||
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||
// Test whether the iterator is empty.
|
||||
|
||||
let skipped = unsafe {
|
||||
let start = self.pos;
|
||||
let stop = start + index - 0x1;
|
||||
if n >= self.len { return None };
|
||||
|
||||
self.buf.get_unchecked_mut(start..stop)
|
||||
};
|
||||
// Get the indeces of the involved items.
|
||||
|
||||
let start = self.pos;
|
||||
let end = start + n;
|
||||
|
||||
// SAFETY: `MaybeUninit<T>` is transparent to `T`.
|
||||
let base = self.buf.as_mut_ptr() as *mut T;
|
||||
|
||||
// Drop each skipped element.
|
||||
|
||||
unsafe { drop_in_place(skipped) };
|
||||
for i in start..end {
|
||||
let item = unsafe { base.add(i) };
|
||||
|
||||
// Read the final element.
|
||||
// SAFETY: We guarantee that all items in the range
|
||||
//
|
||||
// self.pos..self.pos + self.len
|
||||
//
|
||||
// are alive (and initialised).
|
||||
unsafe { drop_in_place(item) };
|
||||
}
|
||||
|
||||
// SAFETY: `index` has been tested to be within
|
||||
// bounds, and the element at that position is also
|
||||
// guaranteed to still be alive.
|
||||
let item = unsafe { self.buf.get_unchecked(index).assume_init_read() };
|
||||
// Read the final value.
|
||||
|
||||
self.len -= index;
|
||||
self.pos += index;
|
||||
let item = unsafe { base.add(end) };
|
||||
|
||||
Some(item)
|
||||
// SAFETY: We guarantee that all items in the range
|
||||
//
|
||||
// self.pos..self.pos + self.len
|
||||
//
|
||||
// are alive (and initialised).
|
||||
let value = unsafe { item.read() };
|
||||
|
||||
// Update counters.
|
||||
|
||||
// SAFETY: This cannot overflow as `n` has been
|
||||
// tested to be less than `self.len`, which itself
|
||||
// cannot be greater than `isize::MAX`.
|
||||
let count = unsafe { n.unchecked_add(0x1) };
|
||||
|
||||
// SAFETY: We have tested that there are at least
|
||||
// `count` elements left.
|
||||
unsafe { self.advance_by_unchecked(count) };
|
||||
|
||||
// Return the value.
|
||||
|
||||
Some(value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let rem = unsafe { self.len.unchecked_sub(self.pos) };
|
||||
let len = self.len;
|
||||
(len, Some(len))
|
||||
}
|
||||
|
||||
(rem, Some(rem))
|
||||
#[inline(always)]
|
||||
fn count(self) -> usize {
|
||||
// NOTE: Elements are dropped automatically.
|
||||
self.len
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_sorted(self) -> bool
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
self.as_slice().is_sorted()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_sorted_by<F: FnMut(&Self::Item, &Self::Item) -> bool>(self, compare: F) -> bool {
|
||||
self.as_slice().is_sorted_by(compare)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,32 +6,46 @@
|
|||
// can obtain one at:
|
||||
// <https://mozilla.org/MPL/2.0/>.
|
||||
|
||||
use core::str::FromStr;
|
||||
use oct::string;
|
||||
use oct::string::String;
|
||||
use oct::vec::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_vec_iter_clone() {
|
||||
let data = String::<0x9>::from_str("fran\u{00E7}ais").unwrap();
|
||||
let data: String::<0xF> = string!("fran\u{00E7}aise");
|
||||
|
||||
let mut data0 = data.into_bytes().into_iter();
|
||||
assert_eq!(data.len(), 0xA);
|
||||
assert_eq!(data.as_bytes(), b"fran\xC3\xA7aise");
|
||||
|
||||
let _ = data0.nth(0x4);
|
||||
let mut iter0 = data.into_bytes().into_iter();
|
||||
|
||||
let mut data1 = data0.clone();
|
||||
assert_eq!(iter0.len(), 0xA);
|
||||
assert_eq!(iter0.as_slice(), b"fran\xC3\xA7aise");
|
||||
|
||||
assert_eq!(data0.next(), Some(0xC3));
|
||||
assert_eq!(data1.next(), Some(0xC3));
|
||||
assert_eq!(data0.next(), Some(0xA7));
|
||||
assert_eq!(data1.next(), Some(0xA7));
|
||||
assert_eq!(data0.next(), Some(b'a'));
|
||||
assert_eq!(data1.next(), Some(b'a'));
|
||||
assert_eq!(data0.next(), Some(b'i'));
|
||||
assert_eq!(data1.next(), Some(b'i'));
|
||||
assert_eq!(data0.next(), Some(b's'));
|
||||
assert_eq!(data1.next(), Some(b's'));
|
||||
assert_eq!(data0.next(), None);
|
||||
assert_eq!(data1.next(), None);
|
||||
assert_eq!(iter0.nth(0x3), Some(b'n'));
|
||||
|
||||
assert_eq!(iter0.len(), 0x6);
|
||||
assert_eq!(iter0.as_slice(), b"\xC3\xA7aise");
|
||||
|
||||
let mut iter1 = iter0.clone();
|
||||
|
||||
assert_eq!(iter1.len(), 0x6);
|
||||
assert_eq!(iter1.as_slice(), b"\xC3\xA7aise");
|
||||
|
||||
assert_eq!(iter0.next(), Some(0xC3));
|
||||
assert_eq!(iter1.next(), Some(0xC3));
|
||||
assert_eq!(iter0.next(), Some(0xA7));
|
||||
assert_eq!(iter1.next(), Some(0xA7));
|
||||
assert_eq!(iter0.next(), Some(b'a'));
|
||||
assert_eq!(iter1.next(), Some(b'a'));
|
||||
assert_eq!(iter0.next(), Some(b'i'));
|
||||
assert_eq!(iter1.next(), Some(b'i'));
|
||||
assert_eq!(iter0.next(), Some(b's'));
|
||||
assert_eq!(iter1.next(), Some(b's'));
|
||||
assert_eq!(iter0.next(), Some(b'e'));
|
||||
assert_eq!(iter1.next(), Some(b'e'));
|
||||
assert_eq!(iter0.next(), None);
|
||||
assert_eq!(iter1.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -8,7 +8,33 @@
|
|||
|
||||
//! Vector container and iterators.
|
||||
|
||||
use crate::use_mod;
|
||||
mod into_iter;
|
||||
mod vec;
|
||||
|
||||
use_mod!(pub into_iter);
|
||||
use_mod!(pub vec);
|
||||
pub use into_iter::IntoIter;
|
||||
pub use vec::{__vec, Vec};
|
||||
|
||||
use core::ops::Range;
|
||||
|
||||
#[inline]
|
||||
unsafe fn clone_to_uninit_in_range<T: Clone>(src: *const T, dst: *mut T, range: Range<usize>) {
|
||||
// SAFETY: The caller guarantees a valid range.
|
||||
for i in range.start..range.end {
|
||||
// SAFETY: We guarantee that all items in the range
|
||||
//
|
||||
// 0x0..self.len
|
||||
//
|
||||
// are alive (and initialised).
|
||||
let src_item = unsafe { &*src.add(i) };
|
||||
|
||||
let dst_item = unsafe { dst.add(i) };
|
||||
|
||||
// Clone the item value.
|
||||
|
||||
let value = src_item.clone();
|
||||
|
||||
// Write the item value.
|
||||
|
||||
unsafe { dst_item.write(value) };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ mod test;
|
|||
use crate::decode::{self, Decode, DecodeBorrowed};
|
||||
use crate::encode::{self, Encode, SizedEncode};
|
||||
use crate::error::{CollectionDecodeError, ItemDecodeError, LengthError};
|
||||
use crate::vec::IntoIter;
|
||||
use crate::vec::{clone_to_uninit_in_range, IntoIter};
|
||||
|
||||
use core::borrow::{Borrow, BorrowMut};
|
||||
use core::cmp::Ordering;
|
||||
|
@ -24,11 +24,7 @@ use core::ptr::{copy_nonoverlapping, drop_in_place, null, null_mut};
|
|||
use core::slice::{self, SliceIndex};
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use {
|
||||
alloc::alloc::alloc,
|
||||
alloc::boxed::Box,
|
||||
core::alloc::Layout,
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
|
||||
/// Vector container with maximum length.
|
||||
///
|
||||
|
@ -370,24 +366,24 @@ impl<T, const N: usize> Vec<T, N> {
|
|||
/// The vector is reallocated using the global allocator.
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub fn into_boxed_slice(self) -> Box<[T]> {
|
||||
let (buf, len) = self.into_raw_parts();
|
||||
|
||||
unsafe {
|
||||
let layout = Layout::array::<T>(len).unwrap();
|
||||
let ptr = alloc(layout).cast::<T>();
|
||||
let mut boxed = alloc::vec::Vec::with_capacity(len).into_boxed_slice();
|
||||
|
||||
assert!(!ptr.is_null(), "allocation failed");
|
||||
// SAFETY: `MaybeUninit<T>` is transparent to `T`.
|
||||
let src = buf.as_ptr() as *const T;
|
||||
|
||||
copy_nonoverlapping(buf.as_ptr().cast(), ptr, len);
|
||||
let dst = boxed.as_mut_ptr();
|
||||
|
||||
let slice = core::ptr::slice_from_raw_parts_mut(ptr, len);
|
||||
Box::from_raw(slice)
|
||||
// SAFETY: `boxed` has been allocated with at least
|
||||
// `len` elements.
|
||||
unsafe { copy_nonoverlapping(src, dst, len) };
|
||||
|
||||
// `self.buf` is dropped without destructors being
|
||||
// run.
|
||||
}
|
||||
boxed
|
||||
}
|
||||
|
||||
/// Converts the vector into a dynamically-allocated vector.
|
||||
|
@ -397,7 +393,8 @@ impl<T, const N: usize> Vec<T, N> {
|
|||
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn into_alloc_vec(self) -> alloc::vec::Vec<T> {
|
||||
#[track_caller]
|
||||
pub fn into_vec(self) -> alloc::vec::Vec<T> {
|
||||
self.into_boxed_slice().into_vec()
|
||||
}
|
||||
}
|
||||
|
@ -405,44 +402,54 @@ impl<T, const N: usize> Vec<T, N> {
|
|||
impl<T, const N: usize> AsMut<[T]> for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn as_mut(&mut self) -> &mut [T] {
|
||||
self.as_mut_slice()
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const N: usize> AsRef<[T]> for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &[T] {
|
||||
self.as_slice()
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const N: usize> Borrow<[T]> for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn borrow(&self) -> &[T] {
|
||||
self.as_slice()
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const N: usize> BorrowMut<[T]> for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn borrow_mut(&mut self) -> &mut [T] {
|
||||
self.as_mut_slice()
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone, const N: usize> Clone for Vec<T, N> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
let len = self.len;
|
||||
let mut buf = [const { MaybeUninit::uninit() }; N];
|
||||
|
||||
unsafe {
|
||||
for i in 0x0..self.len() {
|
||||
let value = self.get_unchecked(i).clone();
|
||||
buf.get_unchecked_mut(i).write(value);
|
||||
}
|
||||
// SAFETY: `MaybeUninit<T>` is transparent to `T`.
|
||||
let src = self.buf.as_ptr() as *const T;
|
||||
|
||||
Self::from_raw_parts(buf, self.len())
|
||||
}
|
||||
let dst = buf.as_mut_ptr() as *mut T;
|
||||
|
||||
// SAFETY: The range
|
||||
//
|
||||
// 0x0..len
|
||||
//
|
||||
// defines in and of itself the bounds of valid
|
||||
// elements.
|
||||
unsafe { clone_to_uninit_in_range(src, dst, 0x0..len) };
|
||||
|
||||
// SAFETY: The buffer has been initialised in the
|
||||
// provided range - which does not extend beyond
|
||||
// bounds.
|
||||
unsafe { Self::from_raw_parts(buf, len) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -486,14 +493,12 @@ impl<T: Decode, const N: usize> DecodeBorrowed<[T]> for Vec<T, N> { }
|
|||
impl<T, const N: usize> Default for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
unsafe {
|
||||
let buf = [const { MaybeUninit::uninit() }; N];
|
||||
let buf = [const { MaybeUninit::uninit() }; N];
|
||||
|
||||
// SAFETY: The resulting vector is zero lengthed
|
||||
// and does therefore not expose any uninitialised
|
||||
// objects.
|
||||
Self::from_raw_parts(buf, Default::default())
|
||||
}
|
||||
// SAFETY: The resulting vector is zero lengthed
|
||||
// and does therefore not expose any uninitialised
|
||||
// objects.
|
||||
unsafe { Self::from_raw_parts(buf, Default::default()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -518,7 +523,10 @@ impl<T, const N: usize> Drop for Vec<T, N> {
|
|||
fn drop(&mut self) {
|
||||
// Drop every element that is currently alive.
|
||||
|
||||
let remaining = &raw mut *self.as_mut_slice();
|
||||
let remaining = self.as_mut_slice() as *mut [T];
|
||||
|
||||
// SAFETY: Mutable references always point to alive
|
||||
// and initialised objects.
|
||||
unsafe { drop_in_place(remaining) };
|
||||
|
||||
// We do not need to ensure that `self` is in a
|
||||
|
@ -531,7 +539,7 @@ impl<T: Encode, const N: usize> Encode for Vec<T, N> {
|
|||
|
||||
#[inline(always)]
|
||||
fn encode(&self, output: &mut encode::Output) -> Result<(), Self::Error> {
|
||||
self.as_slice().encode(output)
|
||||
(**self).encode(output)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,6 +569,7 @@ impl<T, const N: usize> FromIterator<T> for Vec<T, N> {
|
|||
|
||||
for item in &mut buf {
|
||||
let Some(value) = iter.next() else { break };
|
||||
|
||||
item.write(value);
|
||||
|
||||
len += 0x1;
|
||||
|
@ -573,7 +582,7 @@ impl<T, const N: usize> FromIterator<T> for Vec<T, N> {
|
|||
impl<T: Hash, const N: usize> Hash for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.as_slice().hash(state)
|
||||
(**self).hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -583,7 +592,7 @@ impl<T, I: SliceIndex<[T]>, const N: usize> Index<I> for Vec<T, N> {
|
|||
#[inline(always)]
|
||||
#[track_caller]
|
||||
fn index(&self, index: I) -> &Self::Output {
|
||||
Index::index(self.as_slice(), index)
|
||||
Index::index(&**self, index)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -591,7 +600,7 @@ impl<T, I: SliceIndex<[T]>, const N: usize> IndexMut<I> for Vec<T, N> {
|
|||
#[inline(always)]
|
||||
#[track_caller]
|
||||
fn index_mut(&mut self, index: I) -> &mut Self::Output {
|
||||
IndexMut::index_mut(self.as_mut_slice(), index)
|
||||
IndexMut::index_mut(&mut **self, index)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -602,9 +611,7 @@ impl<T, const N: usize> IntoIterator for Vec<T, N> {
|
|||
|
||||
#[inline(always)]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
let (buf, len) = self.into_raw_parts();
|
||||
|
||||
unsafe { IntoIter::new(buf, len) }
|
||||
IntoIter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -633,35 +640,59 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut Vec<T, N> {
|
|||
impl<T: Ord, const N: usize> Ord for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.as_slice().cmp(other.as_slice())
|
||||
(**self).cmp(&**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq<U>, U, const N: usize, const M: usize> PartialEq<Vec<U, M>> for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Vec<U, M>) -> bool {
|
||||
self.as_slice() == other.as_slice()
|
||||
**self == **other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &Vec<U, M>) -> bool {
|
||||
**self != **other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq<U>, U, const N: usize, const M: usize> PartialEq<[U; M]> for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &[U; M]) -> bool {
|
||||
self == other.as_slice()
|
||||
**self == *other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &[U; M]) -> bool {
|
||||
**self != *other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq<U>, U, const N: usize> PartialEq<[U]> for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &[U]) -> bool {
|
||||
self.as_slice() == other
|
||||
**self == *other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &[U]) -> bool {
|
||||
**self != *other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq<U>, U, const N: usize> PartialEq<&[U]> for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &&[U]) -> bool {
|
||||
self == *other
|
||||
**self == **other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &&[U]) -> bool {
|
||||
**self != **other
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,14 +701,40 @@ impl<T: PartialEq<U>, U, const N: usize> PartialEq<&[U]> for Vec<T, N> {
|
|||
impl<T: PartialEq<U>, U, const N: usize> PartialEq<alloc::vec::Vec<U>> for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &alloc::vec::Vec<U>) -> bool {
|
||||
self.as_slice() == other.as_slice()
|
||||
**self == **other
|
||||
}
|
||||
|
||||
#[expect(clippy::partialeq_ne_impl)]
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &alloc::vec::Vec<U>) -> bool {
|
||||
**self != **other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialOrd, const N: usize, const M: usize> PartialOrd<Vec<T, M>> for Vec<T, N> {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Vec<T, M>) -> Option<Ordering> {
|
||||
self.as_slice().partial_cmp(other.as_slice())
|
||||
(**self).partial_cmp(&**other)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn lt(&self, other: &Vec<T, M>) -> bool {
|
||||
**self < **other
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn le(&self, other: &Vec<T, M>) -> bool {
|
||||
**self <= **other
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gt(&self, other: &Vec<T, M>) -> bool {
|
||||
**self > **other
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ge(&self, other: &Vec<T, M>) -> bool {
|
||||
**self >= **other
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -708,7 +765,7 @@ impl<T, const N: usize> From<Vec<T, N>> for Box<[T]> {
|
|||
impl<T, const N: usize> From<Vec<T, N>> for alloc::vec::Vec<T> {
|
||||
#[inline(always)]
|
||||
fn from(value: Vec<T, N>) -> Self {
|
||||
value.into_alloc_vec()
|
||||
value.into_vec()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -720,3 +777,37 @@ impl<T: PartialEq<U>, U, const N: usize> PartialEq<Vec<U, N>> for alloc::vec::Ve
|
|||
self.as_slice() == other.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This function is used by the `vec` macro
|
||||
// to circumvent itself using code which may be
|
||||
// forbidden by the macro user's lints. This func-
|
||||
// tion is sound, but please do not call it direct-
|
||||
// ly. It is not a breaking change if it is re-
|
||||
// moved.
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub const fn __vec<T, const N: usize, const M: usize>(data: [T; M]) -> Vec<T, N> {
|
||||
assert!(M <= N, "cannot construct vector from literal that is longer");
|
||||
|
||||
let data = ManuallyDrop::new(data);
|
||||
|
||||
let mut buf = [const { MaybeUninit::uninit() }; N];
|
||||
let len = M;
|
||||
|
||||
unsafe {
|
||||
let src = &raw const data as *const T;
|
||||
let dst = buf.as_mut_ptr() as *mut T;
|
||||
|
||||
// SAFETY: The original array is not dropped after
|
||||
// this move, and `len` is equal to the length `M`
|
||||
// of the array. `MaybeUninit<T>` is also trans-
|
||||
// parent to `T`.
|
||||
copy_nonoverlapping(src, dst, len);
|
||||
}
|
||||
|
||||
// SAFETY: `len` does not extend beyond the `M`
|
||||
// elements moved from `data`.
|
||||
unsafe { Vec::from_raw_parts(buf, len) }
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
// can obtain one at:
|
||||
// <https://mozilla.org/MPL/2.0/>.
|
||||
|
||||
use oct::vec;
|
||||
use oct::vec::Vec;
|
||||
|
||||
#[test]
|
||||
|
@ -33,3 +34,12 @@ fn test_vec_from_iter() {
|
|||
[0, 708, 826, 19, 572, 919, 78, 431],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_vec_macro() {
|
||||
let v0: Vec<u8, 0x4> = vec![0xEF; 0x3];
|
||||
let v1: Vec<u8, 0x4> = vec![0xEF, 0xEF, 0xEF];
|
||||
|
||||
assert_eq!(v0, v1);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue