Update readme; Clean up code; Update tests;

This commit is contained in:
Gabriel Bjørnager Jensen 2025-04-01 21:23:19 +02:00
parent c764c4b724
commit dcdec20b64
28 changed files with 79 additions and 173 deletions

View file

@ -3,6 +3,12 @@
This is the changelog of [Oct](https://crates.io/crates/oct/).
See `README.md` for more information.
## 0.20.1
* Update readme
* Clean up code
* Update tests
## 0.20.0
* Remove `Vec::set_len`

View file

@ -9,7 +9,7 @@ members = ["oct", "oct-benchmarks", "oct-macros"]
resolver = "2"
[workspace.package]
version = "0.20.0"
version = "0.20.1"
authors = ["Gabriel Bjørnager Jensen"]
readme = "README.md"
repository = "https://mandelbrot.dk/bjoernager/oct/"

View file

@ -33,8 +33,6 @@ According to my runs on an AMD Ryzen 7 3700X with default settings, these benchm
| `decode_bool` | 1.037 | 1.099 | 1.041 | 1.101 |
| **Total time** → | 12.957 | 11.690 | 9.238 | 21.091 |
| **Total deviation (p.c.)** → | +40 | +27 | ±0 | +128 |
| **Total time** → | 14.456 | 11.624 | 8.800 | 21.509 |
| **Total deviation (p.c.)** → | +64 | +32 | ±0 | +144 |
[Bincode]: https://crates.io/crates/bincode/
[Borsh]: https://crates.io/crates/borsh/

View file

@ -35,12 +35,12 @@ repository.workspace = true
oct = { path = "../oct", version = "0.20", features = ["proc-macro"]}
bincode = "2.0"
rand = "0.8"
rand = "0.9"
rayon = "1.10"
zerocopy = "0.8"
borsh = { version = "1.5", features = ["derive"] }
postcard = { version = "1.0", features = ["use-std"] }
postcard = { version = "1.1", features = ["use-std"] }
serde = { version = "1.0", features = ["derive"] }
[lints]

View file

@ -23,7 +23,7 @@
use core::array;
use core::num::NonZero;
use rand::random;
use rand::distributions::{Distribution, Standard};
use rand::distr::{Distribution, StandardUniform};
use std::time::Instant;
use zerocopy::{Immutable, IntoBytes};
@ -188,8 +188,8 @@ enum Enum {
fn generate_random_data<T>(item_size: usize, value_count: usize) -> impl Iterator<Item = u8>
where
T: Immutable + IntoBytes + Sized,
Standard: Distribution<T>,
T: Immutable + IntoBytes + Sized,
StandardUniform: Distribution<T>,
{
let count = item_size * value_count;

View file

@ -23,7 +23,6 @@ use core::cell::{Cell, LazyCell, RefCell, UnsafeCell};
use core::convert::Infallible;
use core::ffi::{CStr, c_void};
use core::hash::BuildHasher;
use core::hint::unreachable_unchecked;
use core::marker::{PhantomData, PhantomPinned};
use core::net::{
IpAddr,
@ -415,9 +414,7 @@ impl Encode for Infallible {
#[inline(always)]
fn encode(&self, _output: &mut Output) -> Result<(), Self::Error> {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() }
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// A character could not be decoded.
///
@ -37,8 +36,6 @@ impl Error for CharDecodeError { }
impl From<Infallible> for CharDecodeError {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// A collection could not be decoded.
///
@ -67,9 +66,7 @@ where
impl<L, I> From<Infallible> for CollectionDecodeError<L, I> {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// A collection could not be encoded.
///
@ -60,9 +59,7 @@ where
impl<L, I> From<Infallible> for CollectionEncodeError<L, I> {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -11,7 +11,6 @@ use crate::decode::Decode;
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Debug, Display, Formatter};
use core::hint::unreachable_unchecked;
/// An enumeration could not be decoded.
#[derive(Debug, Eq, PartialEq)]
@ -72,9 +71,7 @@ where
impl<T, D, F> From<Infallible> for EnumDecodeError<T, D, F> {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Debug, Display, Formatter};
use core::hint::unreachable_unchecked;
/// An enumeration could not be encoded.
#[derive(Debug, Eq, PartialEq)]
@ -57,9 +56,7 @@ where
impl<D, F> From<Infallible> for EnumEncodeError<D, F> {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -20,7 +20,6 @@ use crate::error::{
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// A generic decoding error type.
///
@ -127,9 +126,7 @@ where
impl From<Infallible> for GenericDecodeError {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() }
unreachable!()
}
}

View file

@ -18,7 +18,6 @@ use core::cell::BorrowError;
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// A generic encoding error type.
///
@ -113,9 +112,7 @@ where
impl From<Infallible> for GenericEncodeError {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() }
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// An input-related error.
///
@ -45,8 +44,6 @@ impl Error for InputError { }
impl From<Infallible> for InputError {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// An [`isize`] value could not be decoded.
///
@ -39,8 +38,6 @@ impl Error for IsizeEncodeError { }
impl From<Infallible> for IsizeEncodeError {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Debug, Display, Formatter};
use core::hint::unreachable_unchecked;
/// A collection's item could not be decoded.
///
@ -49,9 +48,7 @@ where
impl<I, E> From<Infallible> for ItemDecodeError<I, E> {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Debug, Display, Formatter};
use core::hint::unreachable_unchecked;
/// A collection's item could not be encoded.
///
@ -49,9 +48,7 @@ where
impl<I, E> From<Infallible> for ItemEncodeError<I, E> {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// A collection buffer was too small to contain all of its elements.
///
@ -41,8 +40,6 @@ impl Error for LengthError { }
impl From<Infallible> for LengthError {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// A non-zero integer could not be decoded.
///
@ -29,8 +28,6 @@ impl Error for NonZeroDecodeError { }
impl From<Infallible> for NonZeroDecodeError {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
#[derive(Debug, Eq, PartialEq)]
#[must_use]
@ -45,8 +44,6 @@ impl Error for OutputError { }
impl From<Infallible> for OutputError {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -10,7 +10,6 @@ use core::cell::BorrowError;
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// A reference cell could not be encoded.
///
@ -54,8 +53,6 @@ impl<E: Error + 'static> Error for RefCellEncodeError<E> {
impl<E> From<Infallible> for RefCellEncodeError<E> {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// The [`SystemTime`](std::time::SystemTime) type could not represent a UNIX timestamp.
///
@ -34,8 +33,6 @@ impl Error for SystemTimeDecodeError { }
impl From<Infallible> for SystemTimeDecodeError {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// A [`usize`] value could not be decoded.
///
@ -38,8 +37,6 @@ impl Error for UsizeEncodeError { }
impl From<Infallible> for UsizeEncodeError {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -9,7 +9,6 @@
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::hint::unreachable_unchecked;
/// An invalid UTF-8 sequence was encountered.
#[derive(Debug, Eq, PartialEq)]
@ -34,8 +33,6 @@ impl Error for Utf8Error { }
impl From<Infallible> for Utf8Error {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed.
unsafe { unreachable_unchecked() };
unreachable!()
}
}

View file

@ -75,6 +75,8 @@
//! The following is an example of a UDP server/client for geographic data:
//!
//! ```rust
//! # #[cfg(not(miri))]
//! # {
//! use oct::decode::Decode;
//! use oct::encode::{Encode, SizedEncode};
//! use oct::slot::Slot;
@ -177,6 +179,8 @@
//! let response = response_buf.read().unwrap();
//! assert_eq!(response, Response::AtmosphericTemperature(44.4));
//! });
//!
//! # }
//! ```
//!
//! # Feature flags

View file

@ -74,7 +74,7 @@ impl<T, const N: usize> IntoIter<T, N> {
// 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.
// offset in such cases.
self.pos = unsafe { self.pos.unchecked_add(count) };
}
@ -95,16 +95,37 @@ impl<T, const N: usize> IntoIter<T, N> {
self.len = unsafe { self.len.unchecked_sub(count) };
}
/// Gets a slice of the remaining elements.
/// Gets a pointer to the current element.
///
/// If the iterator `self` is currently empty, then the returned pointer will instead be dangling.
#[inline(always)]
pub fn as_slice(&self) -> &[T] {
fn as_ptr(&self) -> *const T {
let pos = self.pos;
let len = 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 { base.add(pos) }
}
/// Gets a mutable pointer to the current element.
///
/// If the iterator `self` is currently empty, then the returned pointer will instead be dangling.
#[inline(always)]
fn as_mut_ptr(&mut self) -> *mut T {
let pos = self.pos;
// SAFETY: `MaybeUninit<T>` is transparent to `T`.
let base = self.buf.as_mut_ptr() as *mut T;
unsafe { base.add(pos) }
}
/// Gets a slice of the remaining elements.
#[inline(always)]
pub fn as_slice(&self) -> &[T] {
let len = self.len;
let ptr = self.as_ptr();
unsafe { slice::from_raw_parts(ptr, len) }
}
@ -112,13 +133,8 @@ impl<T, const N: usize> IntoIter<T, N> {
/// Gets a mutable slice of the remaining elements.
#[inline(always)]
pub fn as_mut_slice(&mut self) -> &mut [T] {
let pos = self.pos;
let len = 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) };
let ptr = self.as_mut_ptr();
unsafe { slice::from_raw_parts_mut(ptr, len) }
}
@ -180,7 +196,9 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
fn next_back(&mut self) -> Option<Self::Item> {
// Test whether the iterator is empty.
if self.len == 0x0 { return None };
if self.len == 0x0 {
return None;
}
// Take the next value.
@ -198,11 +216,6 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
// 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.
@ -213,64 +226,6 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
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)
}
}
impl<T, const N: usize> Drop for IntoIter<T, N> {
@ -302,7 +257,9 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
fn next(&mut self) -> Option<Self::Item> {
// Test whether the iterator is empty.
if self.len == 0x0 { return None };
if self.len == 0x0 {
return None;
}
// Take the next value.
@ -341,19 +298,23 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
fn nth(&mut self, n: usize) -> Option<Self::Item> {
// Test whether the iterator is empty.
if n >= self.len { return None };
if n >= self.len {
return None;
}
// Get the indeces of the involved items.
// Get the indices of the involved items.
let start = self.pos;
let end = start + n;
let drop_start = self.pos;
let drop_end = drop_start + n;
let index = drop_end;
// SAFETY: `MaybeUninit<T>` is transparent to `T`.
let base = self.buf.as_mut_ptr() as *mut T;
// Drop each skipped element.
for i in start..end {
for i in drop_start..drop_end {
let item = unsafe { base.add(i) };
// SAFETY: We guarantee that all items in the range
@ -366,13 +327,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
// Read the final value.
let item = unsafe { base.add(end) };
// SAFETY: We guarantee that all items in the range
//
// self.pos..self.pos + self.len
//
// are alive (and initialised).
let item = unsafe { base.add(index) };
let value = unsafe { item.read() };
// Update counters.

View file

@ -270,7 +270,7 @@ impl<T, const N: usize> Vec<T, N> {
debug_assert!(len <= N, "cannot set length past bounds");
// SAFETY: The caller guarantees that `len` is not
// be freaky.
// freaky.
self.len = len
}