diff --git a/CHANGELOG.md b/CHANGELOG.md
index b46fe18..803fa5e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,40 @@
# Changelog
-This is the changelog of bzipper.
+This is the changelog of Librum.
See `README.md` for more information.
+## 0.12.0
+
+* Support custom errors in `Encode` and `Decode` (using associated `Error` type)
+* Further split `EncodeError` into `IsizeEncodeError`, `UsizeEncodeError`, `CollectionEncodeError`, `RefCellEncodeError`, `ItemEncodeError`, and `EnumEncodeError`
+* Fix the `Encode` implementation of `LinkedList`
+* Further split `DecodeError` into `BoolDecodeError`, `CharDecodeError`, `CStringDecodeError`, `NonZeroDecodeError`, `CollectionDecodeError`, `SystemTimeDecodeError`, `EnumDecodeError`, and `ItemDecodeError`
+* Honour custom discriminant types
+* Add `DecodeBorrowed` trait (implement appropriately)
+* Implement `Decode` for `Cow`
+* Refactor derive macros
+* Update lints
+* Rename test modules from `test` to `tests`
+* Restructure some trait implementations
+* Add `proc-macro` feature flag
+* Add `GenericEncodeError` and `GenericDecodeError` error types for derived traits
+* Add `PrimitiveDiscriminant` trait
+* Lock `Arc` implementations behind atomic widths
+* Add `?Sized` clauses to some `Encode` implementations
+* Update readme
+* Fix doc entry for `SizedStr::new`
+* Update atomic tests
+* Make `SizedEncode` a safe trait
+* Do not automatically implement `Encode` when deriving `SizedEncode`
+* Add `copy_from_slice` method to `SizedSlice`
+* Add `each_ref` and `each_mut` methods to `SizedSlice`
+* Add more benchmarks
+* Remove Ciborium benchmarks
+* Rename project to *Librum*
+* Rename `bzipper` crate to `librum`
+* Rename `bzipper_macros` crate to `librum-macros`
+* Rename `bzipper_benchmarks` crate to `librum-benchmarks`
+
## 0.11.0
* Add `into_bytes` destructor to `SizedStr`
diff --git a/Cargo.toml b/Cargo.toml
index 99c1dde..ca07297 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
[workspace]
-members = ["bzipper", "bzipper_benchmarks", "bzipper_macros"]
+members = ["librum", "librum-benchmarks", "librum-macros"]
resolver = "2"
[workspace.package]
@@ -7,14 +7,14 @@ authors = ["Gabriel Bjørnager Jensen"]
description = "Binary (de)serialiser."
readme = "README.md"
homepage = "https://achernar.dk/index.php?p=bzipper"
-repository = "https://mandelbrot.dk/bzipper/"
+repository = "https://mandelbrot.dk/librum/"
license = "LGPL-3.0-or-later"
keywords = ["api", "encoding", "io", "network", "no-std"]
categories = ["encoding", "network-programming", "parsing"]
[workspace.lints.clippy]
as_ptr_cast_mut = "forbid"
-as_underscore = "warn"
+as_underscore = "forbid"
assertions_on_result_states = "warn"
bool_to_int_with_if = "warn"
borrow_as_ptr = "forbid"
@@ -90,8 +90,6 @@ mutex_integer = "deny"
needless_bitwise_bool = "deny"
needless_collect = "warn"
needless_continue = "warn"
-needless_pass_by_ref_mut = "warn"
-needless_pass_by_value = "deny"
needless_raw_string_hashes = "warn"
needless_raw_strings = "warn"
no_effect_underscore_binding = "deny"
@@ -111,7 +109,6 @@ read_zero_byte_vec = "deny"
redundant_clone = "deny"
redundant_closure_for_method_calls = "warn"
redundant_else = "warn"
-redundant_pub_crate = "warn"
redundant_type_annotations = "warn"
ref_as_ptr = "deny"
ref_binding_to_reference = "warn"
@@ -142,7 +139,6 @@ unnested_or_patterns = "warn"
unused_async = "warn"
unused_peekable = "warn"
unused_rounding = "warn"
-unused_self = "warn"
use_self = "deny"
used_underscore_binding = "deny"
useless_let_if_seq = "warn"
diff --git a/README.md b/README.md
index af3a3b5..d7d48af 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# bZipper
+# Librum
-bZipper is a Rust crate for cheaply serialising (encoding) and deserialising (decoding) data structures into binary streams
+Librum is a Rust crate for cheaply serialising (encoding) and deserialising (decoding) data structures into binary streams
What separates this crate from others such as [Bincode](https://crates.io/crates/bincode/) or [Postcard](https://crates.io/crates/postcard/) is that this crate is extensively optimised for *just* binary encodings (whilst the mentioned crates specifically use Serde and build on a more abstract data model).
The original goal of this project was specifically to guarantee size constraints for encodings on a per-type basis at compile-time.
@@ -13,81 +13,102 @@ This crate is compatible with `no_std`.
## Performance
-As bZipper is optimised exclusively for a single, binary format, it may outperform other libraries that are more generic in nature.
+As Librum is optimised exclusively for a single, binary format, it may outperform other libraries that are more generic in nature.
-The `bzipper_benchmarks` binary compares multiple scenarios using bZipper and other, similar crates.
-According to my runs on an AMD Ryzen 7 3700X, these benchmarks indicate that bZipper outperform all of the tested crates -- as demonstrated in the following table:
+The `librum-benchmarks` binary compares multiple scenarios using Librum and other, similar crates.
+According to my runs on an AMD Ryzen 7 3700X, these benchmarks indicate that Librum outperform all of the tested crates -- as demonstrated in the following table:
-| Benchmark | [Bincode] | [Borsh] | bZipper | [Ciborium] | [Postcard] |
-| :--------------------------------- | --------: | ------: | ------: | ---------: | ---------: |
-| `encode_u8` | 1.234 | 1.096 | 0.881 | 3.076 | 1.223 |
-| `encode_struct_unit` | 0.000 | 0.000 | 0.000 | 0.516 | 0.000 |
-| `encode_struct_unnamed` | 1.367 | 1.154 | 1.009 | 2.051 | 1.191 |
-| `encode_struct_named` | 4.101 | 1.271 | 1.181 | 9.342 | 1.182 |
-| `encode_enum_unit` | 0.306 | 0.008 | 0.000 | 2.304 | 0.004 |
-| **Total time** → | 7.009 | 3.528 | 3.071 | 17.289 | 3.599 |
-| **Total deviation (p.c.)** → | +128 | +15 | ±0 | +463 | +17 |
+| Benchmark | [Bincode] | [Borsh] | Librum | [Postcard] |
+| :--------------------------------- | --------: | ------: | ------: | ---------: |
+| `encode_u8` | 1.306 | 1.315 | 1.150 | 1.304 |
+| `encode_u32` | 1.321 | 1.317 | 1.146 | 3.016 |
+| `encode_u128` | 2.198 | 2.103 | 1.509 | 6.376 |
+| `encode_struct_unit` | 0.000 | 0.000 | 0.000 | 0.000 |
+| `encode_struct_unnamed` | 1.362 | 1.448 | 1.227 | 2.659 |
+| `encode_struct_named` | 3.114 | 1.530 | 0.969 | 3.036 |
+| `encode_enum_unit` | 0.252 | 0.297 | 0.000 | 0.299 |
+| **Total time** → | 9.553 | 8.010 | 6.001 | 16.691 |
+| **Total deviation (p.c.)** → | +59 | +33 | ±0 | +178 |
[Bincode]: https://crates.io/crates/bincode/
[Borsh]: https://crates.io/crates/borsh/
-[Ciborium]: https://crates.io/crates/ciborium/
[Postcard]: https://crates.io/crates/postcard/
All quantities are measured in seconds unless otherwise noted.
-Please feel free to conduct your own tests of bZipper.
+Please feel free to conduct your own tests of Librum.
## Data model
-Most primitives encode losslessly, with the main exceptions being `usize` and `isize`.
-These are instead first cast as `u16` and `i16`, respectively, due to portability concerns (with respect to embedded systems).
+Most primitives encode losslessly, with the main exceptions being [`usize`] and [`isize`].
+These are instead first cast as [`u16`] and [`i16`], respectively, due to portability concerns (with respect to embedded systems).
See specific types' implementations for notes on their data models.
-**Note that the data model is currently not stabilised,** and may not necessarily be in the near future (before [specialisation](https://github.com/rust-lang/rust/issues/31844/)).
+**Note that the data model is currently not stabilised,** and may not necessarily be in the near future (at least before [specialisation](https://github.com/rust-lang/rust/issues/31844/)).
It may therefore be undesired to store encodings long-term.
## Usage
-This crate revolves around the `Encode` and `Decode` traits which both handle conversions to and from byte streams.
+This crate revolves around the [`Encode`] and [`Decode`] traits which both handle conversions to and from byte streams.
-Many standard types come implemented with bZipper, including most primitives as well as some standard library types such as `Option` and `Result`.
-Some [features](#features-flags) enable an extended set of implementations.
+Many standard types come implemented with Librum, including most primitives as well as some standard library types such as [`Option`] and [`Result`].
+Some [features](#feature-flags) enable an extended set of implementations.
-It is recommended in most cases to simply derive these two traits for custom types (although this is only supported with enumerations and structures – not untagged unions).
+It is recommended in most cases to simply derive these two traits for custom types (although this is only supported with enumerations and structures -- not untagged unions).
Here, each field is *chained* according to declaration order:
-```rust
-use bzipper::{Buf, Decode, Encode, SizedEncode};
+```
+use librum::{Buf, Decode, Encode};
-#[derive(Debug, Decode, PartialEq, SizedEncode)]
-struct IoRegister {
- addr: u32,
- value: u16,
+##[derive(Debug, Decode, Encode, PartialEq)]
+struct Ints {
+ value0: u8,
+ value1: u16,
+ value2: u32,
+ value3: u64,
+ value4: u128,
}
-let mut buf = Buf::new();
+const VALUE: Ints = Ints {
+ value0: 0x00,
+ value1: 0x02_01,
+ value2: 0x06_05_04_03,
+ value3: 0x0E_0D_0C_0B_0A_09_08_07,
+ value4: 0x1E_1D_1C_1B_1A_19_18_17_16_15_14_13_12_11_10_0F,
+};
-buf.write(IoRegister { addr: 0x04000000, value: 0x0402 }).unwrap();
+let mut buf = Buf::with_capacity(0x100);
-assert_eq!(buf.len(), 0x6);
-assert_eq!(buf, [0x04, 0x00, 0x00, 0x00, 0x04, 0x02].as_slice());
+buf.write(VALUE).unwrap();
-assert_eq!(buf.read().unwrap(), IoRegister { addr: 0x04000000, value: 0x0402 });
+assert_eq!(buf.len(), 0x1F);
+
+assert_eq!(
+ buf,
+ [
+ 0x00, 0x02, 0x01, 0x06, 0x05, 0x04, 0x03, 0x0E,
+ 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x1E,
+ 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16,
+ 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F,
+ ].as_slice(),
+);
+
+assert_eq!(buf.read().unwrap(), VALUE);
```
### Buffer types
-The `Encode` and `Decode` traits both rely on streams for carrying the manipulated byte streams.
+The [`Encode`] and [`Decode`] traits both rely on streams for carrying the manipulated bytes.
-These streams are separated into two type: *O-streams* (output streams) and *i-streams* (input streams).
-Often, but not always, the `Buf` type is preferred over directly calling the `encode` and `decode` methods.
+These streams are separated into two type: [*O-streams*](OStream) (output streams) and [*i-streams*](IStream) (input streams).
+The [`Buf`] type can be used to handle these streams.
### Encoding
-To encode an object directly using the `Encode` trait, simply allocate a buffer for the encoding and wrap it in an `OStream` object:
+To encode an object directly using the `Encode` trait, simply allocate a buffer for the encoding and wrap it in an [`OStream`] object:
-```rust
-use bzipper::{Encode, OStream, SizedEncode};
+```
+use librum::{Encode, OStream, SizedEncode};
let mut buf = [0x00; char::MAX_ENCODED_SIZE];
let mut stream = OStream::new(&mut buf);
@@ -99,8 +120,8 @@ assert_eq!(buf, [0x00, 0x00, 0x04, 0x16].as_slice());
Streams can also be used to chain multiple objects together:
-```rust
-use bzipper::{Encode, OStream, SizedEncode};
+```
+use librum::{Encode, OStream, SizedEncode};
let mut buf = [0x0; char::MAX_ENCODED_SIZE * 0x5];
let mut stream = OStream::new(&mut buf);
@@ -122,7 +143,7 @@ assert_eq!(buf, [
]);
```
-If the encoded type additionally implements `SizedEncode`, then the maximum size of any encoding is guaranteed with the `MAX_ENCODED_SIZE` constant.
+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.
Numerical primitives are encoded in big endian (a.k.a. [network order](https://en.wikipedia.org/wiki/Endianness#Networking)) for... reasons.
It is recommended for implementors to follow this convention as well.
@@ -130,10 +151,10 @@ It is recommended for implementors to follow this convention as well.
### Decoding
Decoding works with a similar syntax to encoding.
-To decode a byte array, simply call the `decode` method with an `IStream` object:
+To decode a byte array, simply call the [`decode`](Decode::decode) method with an [`IStream`] object:
-```rust
-use bzipper::{Decode, IStream};
+```
+use librum::{Decode, IStream};
let data = [0x45, 0x54];
let mut stream = IStream::new(&data);
@@ -158,14 +179,14 @@ assert_eq!(<(u8, u8)>::decode(&mut stream).unwrap(), (0x45, 0x54));
A UDP server/client for geographic data:
-```rust
-use bzipper::{Buf, Decode, SizedEncode};
+```
+use librum::{Buf, Encode, Decode, SizedEncode};
use std::io;
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
use std::thread::spawn;
// City, region, etc.:
-#[derive(Clone, Copy, Debug, Decode, Eq, PartialEq, SizedEncode)]
+##[derive(Clone, Copy, Debug, Decode, Encode, Eq, PartialEq, SizedEncode)]
enum Area {
AlQuds,
Byzantion,
@@ -175,7 +196,7 @@ enum Area {
}
// Client-to-server message:
-#[derive(Debug, Decode, PartialEq, SizedEncode)]
+##[derive(Debug, Decode, Encode, PartialEq, SizedEncode)]
enum Request {
AtmosphericHumidity { area: Area },
AtmosphericPressure { area: Area },
@@ -184,7 +205,7 @@ enum Request {
}
// Server-to-client message:
-#[derive(Debug, Decode, PartialEq, SizedEncode)]
+##[derive(Debug, Decode, Encode, PartialEq, SizedEncode)]
enum Response {
AtmosphericHumidity(f64),
AtmosphericPressure(f64), // Pascal
@@ -260,25 +281,28 @@ spawn(move || {
## Feature flags
-bZipper defines the following features:
+Librum defines the following features:
-* `alloc` (default): Enables the `Buf` type and implementations for e.g. `Box` and `Arc`
-* `std` (default): Enables implementations for types such as `Mutex` and `RwLock`
+* *`alloc`: Enables the [`Buf`] type and implementations for e.g. [`Box`](alloc::boxed::Box) and [`Arc`](alloc::sync::Arc)
+* *`proc-macro`: Pulls the procedural macros from the [`librum_macros`](https://crates.io/crates/librum_macros/) crate
+* *`std`: Enables implementations for types such as [`Mutex`](std::sync::Mutex) and [`RwLock`](std::sync::RwLock)
+
+Features marked with * are enabled by default.
## Documentation
-bZipper has its documentation written in-source for use by `rustdoc`.
-See [Docs.rs](https://docs.rs/bzipper/latest/bzipper/) for an on-line, rendered instance.
+Librum has its documentation written in-source for use by `rustdoc`.
+See [Docs.rs](https://docs.rs/librum/latest/librum/) for an on-line, rendered instance.
Currently, these docs make use of some unstable features for the sake of readability.
The nightly toolchain is therefore required when rendering them.
## Contribution
-bZipper does not accept source code contributions at the moment.
+Librum does not accept source code contributions at the moment.
This is a personal choice by the maintainer and may be undone in the future.
-Do however feel free to open up an issue on [`GitLab`](https://gitlab.com/bjoernager/bzipper/issues/) or (preferably) [`GitHub`](https://github.com/bjoernager/bzipper/issues/) if you feel the need to express any concerns over the project.
+Do however feel free to open up an issue on [`GitLab`](https://gitlab.com/bjoernager/librum/issues/) or (preferably) [`GitHub`](https://github.com/bjoernager/librum/issues/) if you feel the need to express any concerns over the project.
## Copyright & Licence
@@ -290,4 +314,4 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this program.
-If not, see .
+If not, see .
\ No newline at end of file
diff --git a/bzipper/src/error/decode_error/mod.rs b/bzipper/src/error/decode_error/mod.rs
deleted file mode 100644
index 28478f6..0000000
--- a/bzipper/src/error/decode_error/mod.rs
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of bZipper.
-//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
-// Lesser General Public License as published by
-// the Free Software Foundation, either version 3
-// of the License, or (at your option) any later
-// version.
-//
-// bZipper is distributed in the hope that it will
-// be useful, but WITHOUT ANY WARRANTY; without
-// even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
-// not, see .
-
-use crate::error::{SizeError, Utf8Error};
-
-use core::error::Error;
-use core::fmt::{self, Display, Formatter};
-
-#[cfg(feature = "alloc")]
-use alloc::boxed::Box;
-
-/// Decode error variants.
-///
-/// These errors may be returned from implementation of [`Decode`](crate::Decode).
-#[derive(Debug)]
-#[non_exhaustive]
-pub enum DecodeError {
- /// Bytes were requested on an empty stream.
- ///
- /// This variant is different from [`SmallBuffer`](Self::SmallBuffer) in that this is exclusively for use by the stream types, whilst `SmallBuffer` is for any other array-like type.
- BadString(Utf8Error),
-
- /// An unspecified error.
- ///
- /// This is mainly useful by third-party implementors if none of the other predefined variants are appropriate.
- #[cfg(feature = "alloc")]
- #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
- CustomError(Box),
-
- /// A boolean encountered a value outside `0` and `1`.
- InvalidBoolean(u8),
-
- /// An invalid code point was encountered.
- ///
- /// This includes surrogate points in the inclusive range `U+D800` to `U+DFFF`, as well as all values larger than `U+10FFFF`.
- InvalidCodePoint(u32),
-
- /// An invalid enumeration descriminant was provided.
- InvalidDiscriminant(isize),
-
- /// The [`SystemTime`](std::time::SystemTime) type could not represent a UNIX timestamp.
- ///
- /// This error should not occur on systems that represent timestamps with at least a signed 64-bits seconds counter.
- #[cfg(feature = "std")]
- #[cfg_attr(doc, doc(cfg(feature = "std")))]
- NarrowSystemTime {
- /// The unrepresentable timestamp.
- timestamp: i64,
- },
-
- /// A non-zero integer had the value `0`.
- NullInteger,
-
- /// A C-like string encountered a null value within bounds.
- #[cfg(feature = "alloc")]
- #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
- NullCString {
- /// The index of the null value.
- index: usize,
- },
-
- /// An array could not hold the requested amount of elements.
- SmallBuffer(SizeError),
-}
-
-impl Display for DecodeError {
- #[inline]
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- use DecodeError::*;
-
- match *self {
- BadString(ref source)
- => write!(f, "bad string: {source}"),
-
- #[cfg(feature = "alloc")]
- CustomError(ref source)
- => write!(f, "{source}"),
-
- InvalidBoolean(value)
- => write!(f, "expected boolean but got `{value:#02X}`"),
-
- InvalidCodePoint(value)
- => write!(f, "code point U+{value:04X} is not defined"),
-
- InvalidDiscriminant(value)
- => write!(f, "discriminant `{value}` is not valid for the given enumeration"),
-
- #[cfg(feature = "std")]
- NarrowSystemTime { timestamp }
- => write!(f, "could not represent `{timestamp}` as a system timestamp"),
-
- NullInteger
- => write!(f, "expected non-zero integer but got `0`"),
-
- #[cfg(feature = "alloc")]
- NullCString { index }
- => write!(f, "expected c string but found null value at '{index}`"),
-
- SmallBuffer(ref source)
- => write!(f, "buffer too small: {source}"),
- }
- }
-}
-
-impl Error for DecodeError {
- #[inline]
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- use DecodeError::*;
-
- match *self {
- BadString(ref source) => Some(source),
-
- #[cfg(feature = "alloc")]
- CustomError(ref source) => Some(source.as_ref()),
-
- SmallBuffer(ref source) => Some(source),
-
- _ => None,
- }
- }
-}
diff --git a/bzipper/src/error/encode_error/mod.rs b/bzipper/src/error/encode_error/mod.rs
deleted file mode 100644
index 4a9d0d2..0000000
--- a/bzipper/src/error/encode_error/mod.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of bZipper.
-//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
-// Lesser General Public License as published by
-// the Free Software Foundation, either version 3
-// of the License, or (at your option) any later
-// version.
-//
-// bZipper is distributed in the hope that it will
-// be useful, but WITHOUT ANY WARRANTY; without
-// even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
-// not, see .
-
-use core::cell::BorrowError;
-use core::error::Error;
-use core::fmt::{self, Display, Formatter};
-
-#[cfg(feature = "alloc")]
-use alloc::boxed::Box;
-
-/// Encode error variants.
-///
-/// These errors may be returned from implementation of [`Encode`](crate::Encode).
-#[derive(Debug)]
-#[non_exhaustive]
-pub enum EncodeError {
- /// A [`RefCell`](core::cell::RefCell) object could not be borrowed.
- BadBorrow(BorrowError),
-
- /// An unspecified error.
- ///
- /// This is mainly useful by third-party implementors if none of the other predefined variants are appropriate.
- #[cfg(feature = "alloc")]
- #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
- CustomError(Box),
-
- /// An `isize` value could not be cast as `i16`.
- IsizeOutOfRange(isize),
-
- /// A `usize` value could not be cast as `u16`.
- UsizeOutOfRange(usize),
-}
-
-impl Display for EncodeError {
- #[inline]
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- use EncodeError::*;
-
- match *self {
- BadBorrow(ref source)
- => write!(f, "could not borrow reference cell: {source}"),
-
- #[cfg(feature = "alloc")]
- CustomError(ref source)
- => write!(f, "{source}"),
-
- IsizeOutOfRange(value)
- => write!(f, "signed size value ({value}) cannot be serialised: must be in the range ({}) to ({})", i16::MIN, i16::MAX),
-
- UsizeOutOfRange(value)
- => write!(f, "unsigned size value ({value}) cannot be serialised: must be at most ({})", u16::MAX),
- }
- }
-}
-
-impl Error for EncodeError {
- #[inline]
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- use EncodeError::*;
-
- match *self {
- // In practice useless.
- BadBorrow(ref source) => Some(source),
-
- #[cfg(feature = "alloc")]
- CustomError(ref source) => Some(source.as_ref()),
-
- _ => None,
- }
- }
-}
diff --git a/bzipper/src/error/mod.rs b/bzipper/src/error/mod.rs
deleted file mode 100644
index a46ccf1..0000000
--- a/bzipper/src/error/mod.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of bZipper.
-//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
-// Lesser General Public License as published by
-// the Free Software Foundation, either version 3
-// of the License, or (at your option) any later
-// version.
-//
-// bZipper is distributed in the hope that it will
-// be useful, but WITHOUT ANY WARRANTY; without
-// even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
-// not, see .
-
-//! Error variants.
-//!
-//! This module defines the error types used by bZipper.
-//! All of these types define the [`Error`](core::error::Error) trait.
-
-use crate::use_mod;
-
-use_mod!(pub decode_error);
-use_mod!(pub encode_error);
-use_mod!(pub size_error);
-use_mod!(pub string_error);
-use_mod!(pub utf16_error);
-use_mod!(pub utf8_error);
diff --git a/bzipper/src/sized_slice/mod.rs b/bzipper/src/sized_slice/mod.rs
deleted file mode 100644
index 2f880c3..0000000
--- a/bzipper/src/sized_slice/mod.rs
+++ /dev/null
@@ -1,552 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of bZipper.
-//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
-// Lesser General Public License as published by
-// the Free Software Foundation, either version 3
-// of the License, or (at your option) any later
-// version.
-//
-// bZipper is distributed in the hope that it will
-// be useful, but WITHOUT ANY WARRANTY; without
-// even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
-// not, see .
-
-#[cfg(test)]
-mod test;
-
-use crate::{
- Decode,
- Encode,
- IStream,
- OStream,
- SizedEncode,
- SizedIter,
-};
-use crate::error::{DecodeError, EncodeError, SizeError};
-
-use core::borrow::{Borrow, BorrowMut};
-use core::cmp::Ordering;
-use core::fmt::{self, Debug, Formatter};
-use core::hash::{Hash, Hasher};
-use core::mem::MaybeUninit;
-use core::ops::{Deref, DerefMut, Index, IndexMut};
-use core::ptr::copy_nonoverlapping;
-use core::slice;
-use core::slice::{Iter, IterMut, SliceIndex};
-
-#[cfg(feature = "alloc")]
-use alloc::alloc::{alloc, Layout};
-
-#[cfg(feature = "alloc")]
-use alloc::boxed::Box;
-
-#[cfg(feature = "alloc")]
-use alloc::vec::Vec;
-
-/// Stack-allocated vector with maximum length.
-///
-/// This type is intended as an [sized-encodable](SizedEncode) alternative to [`Vec`] for cases where [arrays](array) may not be wanted.
-///
-/// Note that this type is immutable in the sense that it does **not** define methods like `push` and `pop`, unlike `Vec`.
-///
-/// See [`SizedStr`](crate::SizedStr) for an equivalent alternative to [`String`](alloc::string::String).
-///
-/// # Examples
-///
-/// All instances of this type with the same `T` and `N` also have the exact same layout:
-///
-/// ```
-/// use bzipper::SizedSlice;
-///
-/// let vec0 = SizedSlice::::try_from([0x3].as_slice()).unwrap();
-/// let vec1 = SizedSlice::::try_from([0x3, 0x2].as_slice()).unwrap();
-/// let vec2 = SizedSlice::::try_from([0x3, 0x2, 0x4].as_slice()).unwrap();
-/// let vec3 = SizedSlice::::try_from([0x3, 0x2, 0x4, 0x3].as_slice()).unwrap();
-///
-/// assert_eq!(size_of_val(&vec0), size_of_val(&vec1));
-/// assert_eq!(size_of_val(&vec0), size_of_val(&vec2));
-/// assert_eq!(size_of_val(&vec0), size_of_val(&vec3));
-/// assert_eq!(size_of_val(&vec1), size_of_val(&vec2));
-/// assert_eq!(size_of_val(&vec1), size_of_val(&vec3));
-/// assert_eq!(size_of_val(&vec2), size_of_val(&vec3));
-/// ```
-pub struct SizedSlice {
- buf: [MaybeUninit; N],
- len: usize,
-}
-
-impl SizedSlice {
- /// Constructs a fixed-size vector from raw parts.
- ///
- /// The provided parts are not tested in any way.
- ///
- /// # Safety
- ///
- /// The value of `len` may not exceed that of `N`.
- /// Additionally, all elements of `buf` in the range specified by `len` must be initialised.
- ///
- /// If any of these requirements are violated, behaviour is undefined.
- #[inline(always)]
- #[must_use]
- pub const unsafe fn from_raw_parts(buf: [MaybeUninit; N], len: usize) -> Self {
- debug_assert!(len <= N, "cannot construct vector longer than its capacity");
-
- Self { buf, len }
- }
-
- /// Sets the length of the vector.
- ///
- /// The provided length is not tested in any way.
- ///
- /// # Safety
- ///
- /// The new length `len` may not be larger than `N`.
- ///
- /// It is only valid to enlarge vectors if `T` supports being in a purely uninitialised state.
- /// Such is permitted with e.g. [`MaybeUninit`].
- #[inline(always)]
- pub const unsafe fn set_len(&mut self, len: usize) {
- debug_assert!(len <= N, "cannot set length past bounds");
-
- self.len = len
- }
-
- /// Gets a pointer to the first element.
- ///
- /// The pointed-to element may not necessarily be initialised.
- /// See [`len`](Self::len) for more information.
- #[inline(always)]
- #[must_use]
- pub const fn as_ptr(&self) -> *const T {
- self.buf.as_ptr().cast()
- }
-
- /// Gets a mutable pointer to the first element.
- ///
- /// The pointed-to element may not necessarily be initialised.
- /// See [`len`](Self::len) for more information.
- #[inline(always)]
- #[must_use]
- pub const fn as_mut_ptr(&mut self) -> *mut T {
- self.buf.as_mut_ptr().cast()
- }
-
- /// Borrows the vector as a slice.
- ///
- /// The range of the returned slice only includes the elements specified by [`len`](Self::len).
- #[inline(always)]
- #[must_use]
- pub const fn as_slice(&self) -> &[T] {
- let ptr = self.as_ptr();
- let len = self.len();
-
- unsafe { slice::from_raw_parts(ptr, len) }
- }
-
- /// Borrows the vector as a mutable slice.
- ///
- /// The range of the returned slice only includes the elements specified by [`len`](Self::len).
- #[inline(always)]
- #[must_use]
- pub const fn as_mut_slice(&mut self) -> &mut [T] {
- let ptr = self.as_mut_ptr();
- let len = self.len();
-
- unsafe { slice::from_raw_parts_mut(ptr, len) }
- }
-
- /// Returns the total capacity of the vector.
- ///
- /// By definition, this is always exactly equal to the value of `N`.
- #[expect(clippy::unused_self)]
- #[inline(always)]
- #[must_use]
- pub const fn capacity(&self) -> usize {
- N
- }
-
- /// Returns the length of the vector.
- ///
- /// This value may necessarily be smaller than `N`.
- #[inline(always)]
- #[must_use]
- pub const fn len(&self) -> usize {
- self.len
- }
-
- /// Checks if the vector is empty, i.e. no elements are recorded.
- ///
- /// Note that the internal buffer may still contain objects that have been "shadowed" by setting a smaller length with [`len`](Self::len).
- #[inline(always)]
- #[must_use]
- pub const fn is_empty(&self) -> bool {
- self.len() == 0x0
- }
-
- /// Checks if the vector is full, i.e. it cannot hold any more elements.
- #[inline(always)]
- #[must_use]
- pub const fn is_full(&self) -> bool {
- self.len() == self.capacity()
- }
-
- /// Destructs the vector into its raw parts.
- ///
- /// The returned values are valid to pass on to [`from_raw_parts`](Self::from_raw_parts).
- #[inline(always)]
- #[must_use]
- pub const fn into_raw_parts(self) -> ([MaybeUninit; N], usize) {
- let Self { buf, len } = self;
- (buf, len)
- }
-
- /// Converts the vector into a boxed slice.
- ///
- /// The vector is reallocated using the global allocator.
- #[cfg(feature = "alloc")]
- #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
- #[must_use]
- pub fn into_boxed_slice(self) -> Box<[T]> {
- let (buf, len) = self.into_raw_parts();
-
- unsafe {
- let layout = Layout::array::(len).unwrap();
- let ptr = alloc(layout).cast::();
-
- assert!(!ptr.is_null(), "allocation failed");
-
- copy_nonoverlapping(buf.as_ptr().cast(), ptr, len);
-
- let slice = core::ptr::slice_from_raw_parts_mut(ptr, len);
- Box::from_raw(slice)
-
- // `self.buf` is dropped without destructors being
- // run.
- }
- }
-
- /// Converts the vector into a dynamic vector.
- ///
- /// The vector is reallocated using the global allocator.
- #[cfg(feature = "alloc")]
- #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
- #[inline(always)]
- #[must_use]
- pub fn into_vec(self) -> Vec {
- self.into_boxed_slice().into_vec()
- }
-}
-
-impl SizedSlice {
- /// Constructs an empty, fixed-size vector.
- #[inline]
- pub fn new(data: &[T]) -> Result {
- let mut buf: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() };
-
- let len = data.len();
- if len > N { return Err(SizeError { req: len, len: N }) };
-
- for (item, value) in buf.iter_mut().zip(data.iter()) {
- item.write(value.clone());
- }
-
- Ok(Self { buf, len })
- }
-}
-
-impl AsMut<[T]> for SizedSlice {
- #[inline(always)]
- fn as_mut(&mut self) -> &mut [T] {
- self.as_mut_slice()
- }
-}
-
-impl AsRef<[T]> for SizedSlice {
- #[inline(always)]
- fn as_ref(&self) -> &[T] {
- self.as_slice()
- }
-}
-
-impl Borrow<[T]> for SizedSlice {
- #[inline(always)]
- fn borrow(&self) -> &[T] {
- self.as_slice()
- }
-}
-
-impl BorrowMut<[T]> for SizedSlice {
- #[inline(always)]
- fn borrow_mut(&mut self) -> &mut [T] {
- self.as_mut_slice()
- }
-}
-
-impl Clone for SizedSlice {
- #[inline]
- fn clone(&self) -> Self {
- unsafe {
- let mut buf: [MaybeUninit; N] = MaybeUninit::uninit().assume_init();
-
- for i in 0x0..self.len() {
- let value = self.get_unchecked(i).clone();
- buf.get_unchecked_mut(i).write(value);
- }
-
- Self { buf, len: self.len }
- }
- }
-}
-
-impl Debug for SizedSlice {
- #[inline(always)]
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- Debug::fmt(self.as_slice(), f)
- }
-}
-
-impl Default for SizedSlice {
- #[inline(always)]
- fn default() -> Self {
- Self { buf: unsafe { MaybeUninit::uninit().assume_init() }, len: 0x0 }
- }
-}
-
-impl Deref for SizedSlice {
- type Target = [T];
-
- #[inline(always)]
- fn deref(&self) -> &Self::Target {
- self.as_slice()
- }
-}
-
-impl DerefMut for SizedSlice {
- #[inline(always)]
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.as_mut_slice()
- }
-}
-
-impl Decode for SizedSlice {
- #[inline]
- fn decode(stream: &mut IStream) -> Result {
- let len = Decode::decode(stream)?;
- if len > N { return Err(DecodeError::SmallBuffer(SizeError { req: len, len: N })) };
-
- let mut buf: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() };
-
- for item in &mut buf {
- let value = Decode::decode(stream)?;
-
- item.write(value);
- }
-
- Ok(Self { buf, len })
- }
-}
-
-impl Encode for SizedSlice {
- #[inline(always)]
- fn encode(&self, stream: &mut OStream) -> Result<(), EncodeError> {
- self.as_slice().encode(stream)
- }
-}
-
-impl Eq for SizedSlice { }
-
-impl From<[T; N]> for SizedSlice {
- #[inline(always)]
- fn from(value: [T; N]) -> Self {
- unsafe {
- let buf = value.as_ptr().cast::<[MaybeUninit; N]>().read();
-
- Self { buf, len: N }
- }
- }
-}
-
-impl FromIterator for SizedSlice {
- #[inline]
- fn from_iter>(iter: I) -> Self {
- let mut iter = iter.into_iter();
-
- let mut buf: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() };
- let mut len = 0x0;
-
- for item in &mut buf {
- let Some(value) = iter.next() else { break };
- item.write(value);
-
- len += 0x1;
- }
-
- Self { buf, len }
- }
-}
-
-impl Hash for SizedSlice {
- #[inline(always)]
- fn hash(&self, state: &mut H) {
- for v in self {
- v.hash(state);
- }
- }
-}
-
-impl, const N: usize> Index for SizedSlice {
- type Output = I::Output;
-
- #[inline(always)]
- fn index(&self, index: I) -> &Self::Output {
- self.get(index).unwrap()
- }
-}
-
-impl, const N: usize> IndexMut for SizedSlice {
- #[inline(always)]
- fn index_mut(&mut self, index: I) -> &mut Self::Output {
- self.get_mut(index).unwrap()
- }
-}
-
-impl IntoIterator for SizedSlice {
- type Item = T;
-
- type IntoIter = SizedIter;
-
- #[inline(always)]
- fn into_iter(self) -> Self::IntoIter {
- let Self { buf, len } = self;
-
- unsafe { SizedIter::new(buf, len) }
- }
-}
-
-impl<'a, T, const N: usize> IntoIterator for &'a SizedSlice {
- type Item = &'a T;
-
- type IntoIter = Iter<'a, T>;
-
- #[inline(always)]
- fn into_iter(self) -> Self::IntoIter {
- self.iter()
- }
-}
-
-impl<'a, T, const N: usize> IntoIterator for &'a mut SizedSlice {
- type Item = &'a mut T;
-
- type IntoIter = IterMut<'a, T>;
-
- #[inline(always)]
- fn into_iter(self) -> Self::IntoIter {
- self.iter_mut()
- }
-}
-
-impl Ord for SizedSlice {
- #[inline(always)]
- fn cmp(&self, other: &Self) -> Ordering {
- self.as_slice().cmp(other.as_slice())
- }
-}
-
-impl, U: PartialEq, const N: usize, const M: usize> PartialEq> for SizedSlice {
- #[inline(always)]
- fn eq(&self, other: &SizedSlice) -> bool {
- self.as_slice() == other.as_slice()
- }
-}
-
-impl, U: PartialEq, const N: usize, const M: usize> PartialEq<[U; M]> for SizedSlice {
- #[inline(always)]
- fn eq(&self, other: &[U; M]) -> bool {
- self.as_slice() == other.as_slice()
- }
-}
-
-impl, U: PartialEq, const N: usize> PartialEq<&[U]> for SizedSlice {
- #[inline(always)]
- fn eq(&self, other: &&[U]) -> bool {
- self.as_slice() == *other
- }
-}
-
-#[cfg(feature = "alloc")]
-#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
-impl, U: PartialEq, const N: usize> PartialEq> for SizedSlice {
- #[inline(always)]
- fn eq(&self, other: &Vec) -> bool {
- self.as_slice() == other.as_slice()
- }
-}
-
-impl PartialOrd> for SizedSlice {
- #[inline(always)]
- fn partial_cmp(&self, other: &SizedSlice) -> Option {
- self.as_slice().partial_cmp(other.as_slice())
- }
-}
-
-impl PartialOrd<[T; M]> for SizedSlice {
- #[inline(always)]
- fn partial_cmp(&self, other: &[T; M]) -> Option {
- self.as_slice().partial_cmp(other.as_slice())
- }
-}
-
-impl PartialOrd<&[T]> for SizedSlice {
- #[inline(always)]
- fn partial_cmp(&self, other: &&[T]) -> Option {
- self.as_slice().partial_cmp(*other)
- }
-}
-
-#[cfg(feature = "alloc")]
-#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
-impl PartialOrd> for SizedSlice {
- #[inline(always)]
- fn partial_cmp(&self, other: &Vec) -> Option {
- self.as_slice().partial_cmp(other.as_slice())
- }
-}
-
-unsafe impl SizedEncode for SizedSlice {
- const MAX_ENCODED_SIZE: usize = T::MAX_ENCODED_SIZE * N;
-}
-
-impl TryFrom<&[T]> for SizedSlice {
- type Error = SizeError;
-
- #[inline(always)]
- fn try_from(value: &[T]) -> Result {
- Self::new(value)
- }
-}
-
-#[cfg(feature = "alloc")]
-#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
-impl From> for Box<[T]> {
- #[inline(always)]
- fn from(value: SizedSlice) -> Self {
- value.into_boxed_slice()
- }
-}
-
-#[cfg(feature = "alloc")]
-#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
-impl From> for Vec {
- #[inline(always)]
- fn from(value: SizedSlice) -> Self {
- value.into_vec()
- }
-}
diff --git a/bzipper_macros/src/discriminant/mod.rs b/bzipper_macros/src/discriminant/mod.rs
deleted file mode 100644
index a5d6a95..0000000
--- a/bzipper_macros/src/discriminant/mod.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of bZipper.
-//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
-// Lesser General Public License as published by
-// the Free Software Foundation, either version 3
-// of the License, or (at your option) any later
-// version.
-//
-// bZipper is distributed in the hope that it will
-// be useful, but WITHOUT ANY WARRANTY; without
-// even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
-// not, see .
-
-use proc_macro2::TokenStream;
-use quote::ToTokens;
-use syn::{Expr, Lit};
-
-/// An enumeration discriminant.
-#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
-#[repr(transparent)]
-pub struct Discriminant(pub isize);
-
-impl Discriminant {
- /// Parses the expression as a discriminant value.
- ///
- /// # Panics
- ///
- /// This constructor will panic if the provided expression is not a valid `isize` literal.
- #[inline]
- #[must_use]
- pub fn parse(expr: &Expr) -> Self {
- let Expr::Lit(ref expr) = *expr else {
- panic!("expected literal expression for discriminant value");
- };
-
- let Lit::Int(ref expr) = expr.lit else {
- panic!("expected integer literal for discriminant value");
- };
-
- let value = expr.base10_parse::()
- .expect("expected `isize` literal for discriminant value");
-
- Self(value)
- }
-}
-
-impl ToTokens for Discriminant {
- #[inline(always)]
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.0.to_tokens(tokens);
- }
-}
diff --git a/bzipper_macros/src/impls/decode_enum.rs b/bzipper_macros/src/impls/decode_enum.rs
deleted file mode 100644
index c773de2..0000000
--- a/bzipper_macros/src/impls/decode_enum.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of bZipper.
-//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
-// Lesser General Public License as published by
-// the Free Software Foundation, either version 3
-// of the License, or (at your option) any later
-// version.
-//
-// bZipper is distributed in the hope that it will
-// be useful, but WITHOUT ANY WARRANTY; without
-// even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
-// not, see .
-
-use crate::DiscriminantIter;
-
-use proc_macro2::TokenStream;
-use quote::quote;
-use syn::{DataEnum, Fields, Token, Variant};
-use syn::punctuated::Punctuated;
-
-#[must_use]
-pub fn decode_enum(data: &DataEnum) -> TokenStream {
- let mut match_arms = Punctuated::::new();
-
- for (discriminant, variant) in DiscriminantIter::new(&data.variants) {
- let mut chain_commands = Punctuated::::new();
-
- for field in &variant.fields {
- let command = field.ident
- .as_ref()
- .map_or_else(
- || quote! { ::bzipper::Decode::decode(stream)? },
- |field_name| quote! { #field_name: ::bzipper::Decode::decode(stream)? },
- );
-
- chain_commands.push(command);
- }
-
- let value = match *variant {
- Variant { ident: ref variant_name, fields: Fields::Named( ..), .. } => quote! { Self::#variant_name { #chain_commands } },
- Variant { ident: ref variant_name, fields: Fields::Unnamed(..), .. } => quote! { Self::#variant_name(#chain_commands) },
- Variant { ident: ref variant_name, fields: Fields::Unit, .. } => quote! { Self::#variant_name },
- };
-
- match_arms.push(quote! { #discriminant => #value });
- }
-
- match_arms.push(quote! {
- value => return ::core::result::Result::Err(::bzipper::error::DecodeError::InvalidDiscriminant(value))
- });
-
- quote! {
- #[inline]
- fn decode(stream: &mut ::bzipper::IStream) -> ::core::result::Result {
- let value = match (::decode(stream)?) { #match_arms };
- Ok(value)
- }
- }
-}
diff --git a/bzipper_macros/src/impls/decode_struct.rs b/bzipper_macros/src/impls/decode_struct.rs
deleted file mode 100644
index 9688e91..0000000
--- a/bzipper_macros/src/impls/decode_struct.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of bZipper.
-//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
-// Lesser General Public License as published by
-// the Free Software Foundation, either version 3
-// of the License, or (at your option) any later
-// version.
-//
-// bZipper is distributed in the hope that it will
-// be useful, but WITHOUT ANY WARRANTY; without
-// even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
-// not, see .
-
-use proc_macro2::TokenStream;
-use quote::quote;
-use syn::{DataStruct, Fields, Token};
-use syn::punctuated::Punctuated;
-
-#[must_use]
-pub fn decode_struct(data: &DataStruct) -> TokenStream {
- let mut chain_commands = Punctuated::::new();
-
- for field in &data.fields {
- let command = field.ident
- .as_ref()
- .map_or_else(
- || quote! { ::bzipper::Decode::decode(stream)? },
- |field_name| quote! { #field_name: ::bzipper::Decode::decode(stream)? },
- );
-
- chain_commands.push(command);
- }
-
- let value = match data.fields {
- Fields::Named( ..) => quote! { Self { #chain_commands } },
- Fields::Unnamed(..) => quote! { Self(#chain_commands) },
- Fields::Unit => quote! { Self },
- };
-
- quote! {
- #[inline]
- fn decode(stream: &mut ::bzipper::IStream) -> ::core::result::Result {
- let value = #value;
- Ok(value)
- }
- }
-}
diff --git a/bzipper_macros/src/impls/encode_enum.rs b/bzipper_macros/src/impls/encode_enum.rs
deleted file mode 100644
index 7ecf3d5..0000000
--- a/bzipper_macros/src/impls/encode_enum.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of bZipper.
-//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
-// Lesser General Public License as published by
-// the Free Software Foundation, either version 3
-// of the License, or (at your option) any later
-// version.
-//
-// bZipper is distributed in the hope that it will
-// be useful, but WITHOUT ANY WARRANTY; without
-// even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
-// not, see .
-
-use crate::DiscriminantIter;
-
-use proc_macro2::{Span, TokenStream};
-use quote::quote;
-use syn::{
- DataEnum,
- Fields,
- Ident,
- Variant,
-};
-
-#[must_use]
-pub fn encode_enum(data: &DataEnum) -> TokenStream {
- let mut match_arms = Vec::new();
-
- // Iterate over each variant and give it a unique
- // encoding scheme.
- for (discriminant, variant) in DiscriminantIter::new(&data.variants) {
- // The original identifiers of the fields:
- let mut field_names = Vec::new();
-
- // The captured field identifiers:
- let mut field_captures = Vec::new();
-
- for (index, field) in variant.fields.iter().enumerate() {
- let capture = Ident::new(&format!("value{index}"), Span::call_site());
-
- field_names.push(&field.ident);
- field_captures.push(capture);
- }
-
- let pattern = match *variant {
- Variant { ident: ref variant_name, fields: Fields::Named( ..), .. } => quote! { Self::#variant_name { #(#field_names: ref #field_captures, )* } },
- Variant { ident: ref variant_name, fields: Fields::Unnamed(..), .. } => quote! { Self::#variant_name(#(ref #field_captures)*) },
- Variant { ident: ref variant_name, fields: Fields::Unit, .. } => quote! { Self::#variant_name },
- };
-
- match_arms.push(quote! {
- #pattern => {
- ::bzipper::Encode::encode(discriminant, stream)?;
- #(::bzipper::Encode::encode(#field_captures, stream)?;)*
- }
- });
- }
-
- quote! {
- #[inline]
- fn encode(&self, stream: &mut ::bzipper::OStream) -> ::core::result::Result<(), ::bzipper::error::EncodeError> {
- match *self {
- #(#match_arms)*
- }
-
- Ok(())
- }
- }
-}
diff --git a/bzipper_macros/src/impls/encode_struct.rs b/bzipper_macros/src/impls/encode_struct.rs
deleted file mode 100644
index e853e44..0000000
--- a/bzipper_macros/src/impls/encode_struct.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of bZipper.
-//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
-// Lesser General Public License as published by
-// the Free Software Foundation, either version 3
-// of the License, or (at your option) any later
-// version.
-//
-// bZipper is distributed in the hope that it will
-// be useful, but WITHOUT ANY WARRANTY; without
-// even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
-// not, see .
-
-use proc_macro2::TokenStream;
-use quote::{quote, ToTokens};
-use syn::{DataStruct, Index};
-
-#[must_use]
-pub fn encode_struct(data: &DataStruct) -> TokenStream {
- let mut fields = Vec::new();
-
- for (index, field) in data.fields.iter().enumerate() {
- let name = field.ident
- .as_ref()
- .map_or_else(|| Index::from(index).to_token_stream(), ToTokens::to_token_stream);
-
- fields.push(name);
- }
-
- quote! {
- #[inline]
- fn encode(&self, stream: &mut ::bzipper::OStream) -> ::core::result::Result<(), ::bzipper::error::EncodeError> {
- #(::bzipper::Encode::encode(&self.#fields, stream)?;)*
-
- Ok(())
- }
- }
-}
diff --git a/bzipper_macros/src/impls/sized_encode_enum.rs b/bzipper_macros/src/impls/sized_encode_enum.rs
deleted file mode 100644
index 3bfc961..0000000
--- a/bzipper_macros/src/impls/sized_encode_enum.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of bZipper.
-//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
-// Lesser General Public License as published by
-// the Free Software Foundation, either version 3
-// of the License, or (at your option) any later
-// version.
-//
-// bZipper is distributed in the hope that it will
-// be useful, but WITHOUT ANY WARRANTY; without
-// even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
-// not, see .
-
-use proc_macro2::TokenStream;
-use quote::quote;
-use syn::DataEnum;
-
-#[must_use]
-pub fn sized_encode_enum(data: &DataEnum) -> TokenStream {
- let mut sizes = Vec::new();
-
- // Iterate over each variant and give it a unique
- // encoding scheme.
- for variant in &data.variants {
- let mut field_tys = Vec::new();
-
- for field in &variant.fields {
- field_tys.push(&field.ty);
- }
-
- sizes.push(quote! {
- ::MAX_ENCODED_SIZE
- #(+ <#field_tys as ::bzipper::SizedEncode>::MAX_ENCODED_SIZE)*
- });
- }
-
- quote! {
- const MAX_ENCODED_SIZE: usize = const {
- let mut max_encoded_size = 0x0usize;
-
- #(if #sizes > max_encoded_size { max_encoded_size = #sizes };)*
-
- max_encoded_size
- };
- }
-}
diff --git a/bzipper_macros/src/lib.rs b/bzipper_macros/src/lib.rs
deleted file mode 100644
index e92f8b0..0000000
--- a/bzipper_macros/src/lib.rs
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of bZipper.
-//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
-// Lesser General Public License as published by
-// the Free Software Foundation, either version 3
-// of the License, or (at your option) any later
-// version.
-//
-// bZipper is distributed in the hope that it will
-// be useful, but WITHOUT ANY WARRANTY; without
-// even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
-// not, see .
-
-#![doc(html_logo_url = "https://gitlab.com/bjoernager/bzipper/-/raw/master/doc-icon.svg")]
-
-//! This crate implements procedural macros for [`bZipper`](https://crates.io/crates/bzipper/).
-
-use proc_macro::TokenStream;
-use quote::quote;
-use syn::{Data, DeriveInput};
-
-macro_rules! use_mod {
- ($vis:vis $name:ident) => {
- mod $name;
- $vis use $name::*;
- };
-}
-pub(crate) use use_mod;
-
-use_mod!(discriminant);
-use_mod!(discriminant_iter);
-use_mod!(generic_name);
-
-mod impls;
-
-#[proc_macro_derive(Decode)]
-pub fn derive_decode(input: TokenStream) -> TokenStream {
- let input = syn::parse_macro_input!(input as DeriveInput);
-
- let impl_body = match input.data {
- Data::Enum( ref data) => impls::decode_enum( data),
- Data::Struct(ref data) => impls::decode_struct(data),
-
- Data::Union(..) => panic!("unions cannot derive `Decode`"),
- };
-
- let ty_name = &input.ident;
-
- let generic_params = &input.generics.params;
- let generic_where = &input.generics.where_clause;
-
- let generic_names = GenericName::extract_from(&input.generics);
-
- let output = quote! {
- impl<#generic_params> ::bzipper::Decode for #ty_name<#generic_names>
- #generic_where {
- #impl_body
- }
- };
-
- //panic!("{output}");
-
- output.into()
-}
-
-#[proc_macro_derive(Encode)]
-pub fn derive_encode(input: TokenStream) -> TokenStream {
- let input = syn::parse_macro_input!(input as DeriveInput);
-
- let impl_body = match input.data {
- Data::Enum( ref data) => impls::encode_enum( data),
- Data::Struct(ref data) => impls::encode_struct(data),
-
- Data::Union(..) => panic!("unions cannot derive `Encode`"),
- };
-
- let ty_name = &input.ident;
-
- let generic_params = &input.generics.params;
- let generic_where = &input.generics.where_clause;
-
- let generic_names = GenericName::extract_from(&input.generics);
-
- let output = quote! {
- impl<#generic_params> ::bzipper::Encode for #ty_name<#generic_names>
- #generic_where {
- #impl_body
- }
- };
-
- //panic!("{output}");
-
- output.into()
-}
-
-#[proc_macro_derive(SizedEncode)]
-pub fn derive_sized_encode(input: TokenStream) -> TokenStream {
- let input = syn::parse_macro_input!(input as DeriveInput);
-
- let encode_impl_body = match input.data {
- Data::Enum( ref data) => impls::encode_enum( data),
- Data::Struct(ref data) => impls::encode_struct(data),
-
- Data::Union(..) => panic!("unions can neither derive `Encode` nor `SizedEncode`"),
- };
-
- let sized_encode_impl_body = match input.data {
- Data::Enum( ref data) => impls::sized_encode_enum( data),
- Data::Struct(ref data) => impls::sized_encode_struct(data),
-
- Data::Union(..) => unreachable!(),
- };
-
- let ty_name = &input.ident;
-
- let generic_params = &input.generics.params;
- let generic_where = &input.generics.where_clause;
-
- let generic_names = GenericName::extract_from(&input.generics);
-
- let output = quote! {
- impl<#generic_params> ::bzipper::Encode for #ty_name<#generic_names>
- #generic_where {
- #encode_impl_body
- }
-
- unsafe impl<#generic_params> ::bzipper::SizedEncode for #ty_name<#generic_names>
- #generic_where {
- #sized_encode_impl_body
- }
- };
-
- //panic!("{output}");
-
- output.into()
-}
diff --git a/bzipper_benchmarks/Cargo.toml b/librum-benchmarks/Cargo.toml
similarity index 63%
rename from bzipper_benchmarks/Cargo.toml
rename to librum-benchmarks/Cargo.toml
index 4b1fe83..d14fb86 100644
--- a/bzipper_benchmarks/Cargo.toml
+++ b/librum-benchmarks/Cargo.toml
@@ -1,8 +1,8 @@
[package]
-name = "bzipper_benchmarks"
-version = "0.11.0"
+name = "librum-benchmarks"
+version = "0.12.0"
edition = "2021"
-description = "bZipper benchmarks."
+description = "Librum benchmarks."
authors.workspace = true
readme.workspace = true
@@ -10,11 +10,10 @@ homepage.workspace = true
repository.workspace = true
[dependencies]
-bzipper = { path = "../bzipper", version = "0.11.0" }
+librum = { path = "../librum", version = "0.12.0", features = ["proc-macro"]}
-bincode = "1.3.3"
-ciborium = "0.2.2"
-rand = "0.8.5"
+bincode = "1.3.3"
+rand = "0.8.5"
borsh = { version = "1.5.1", features = ["derive"] }
postcard = { version = "1.0.10", features = ["use-std"] }
diff --git a/bzipper_benchmarks/src/main.rs b/librum-benchmarks/src/main.rs
similarity index 54%
rename from bzipper_benchmarks/src/main.rs
rename to librum-benchmarks/src/main.rs
index 7a8d7a4..f080668 100644
--- a/bzipper_benchmarks/src/main.rs
+++ b/librum-benchmarks/src/main.rs
@@ -15,9 +15,7 @@ macro_rules! benchmark {
borsh: $borsh_op:block$(,)?
- bzipper: $bzipper_op:block$(,)?
-
- ciborium: $ciborium_op:block$(,)?
+ librum: $librum_op:block$(,)?
postcard: $postcard_op:block$(,)?
}$(,)?)+
@@ -53,8 +51,7 @@ macro_rules! benchmark {
let mut total_bincode_duration = 0.0;
let mut total_borsh_duration = 0.0;
- let mut total_bzipper_duration = 0.0;
- let mut total_ciborium_duration = 0.0;
+ let mut total_librum_duration = 0.0;
let mut total_postcard_duration = 0.0;
$({
@@ -64,41 +61,37 @@ macro_rules! benchmark {
let bincode_duration = time! { $bincode_op };
let borsh_duration = time! { $borsh_op };
- let bzipper_duration = time! { $bzipper_op };
- let ciborium_duration = time! { $ciborium_op };
+ let librum_duration = time! { $librum_op };
let postcard_duration = time! { $postcard_op };
eprint!("\u{001B}[000m");
- eprintln!("bincode: {}", format_score(bincode_duration, bzipper_duration));
- eprintln!("borsh: {}", format_score(borsh_duration, bzipper_duration));
- eprintln!("bzipper: {}", format_score(bzipper_duration, bzipper_duration));
- eprintln!("ciborium: {}", format_score(ciborium_duration, bzipper_duration));
- eprintln!("postcard: {}", format_score(postcard_duration, bzipper_duration));
+ eprintln!("bincode: {}", format_score(bincode_duration, librum_duration));
+ eprintln!("borsh: {}", format_score(borsh_duration, librum_duration));
+ eprintln!("librum: {}", format_score(librum_duration, librum_duration));
+ eprintln!("postcard: {}", format_score(postcard_duration, librum_duration));
total_bincode_duration += bincode_duration;
total_borsh_duration += borsh_duration;
- total_bzipper_duration += bzipper_duration;
- total_ciborium_duration += ciborium_duration;
+ total_librum_duration += librum_duration;
total_postcard_duration += postcard_duration;
})*
eprintln!();
eprintln!("\u{001B}[001mtotal score:\u{001B}[022m");
- eprintln!("bincode: {}", format_score(total_bincode_duration, total_bzipper_duration));
- eprintln!("borsh: {}", format_score(total_borsh_duration, total_bzipper_duration));
- eprintln!("bzipper: {}", format_score(total_bzipper_duration, total_bzipper_duration));
- eprintln!("ciborium: {}", format_score(total_ciborium_duration, total_bzipper_duration));
- eprintln!("postcard: {}", format_score(total_postcard_duration, total_bzipper_duration));
+ eprintln!("bincode: {}", format_score(total_bincode_duration, total_librum_duration));
+ eprintln!("borsh: {}", format_score(total_borsh_duration, total_librum_duration));
+ eprintln!("librum: {}", format_score(total_librum_duration, total_librum_duration));
+ eprintln!("postcard: {}", format_score(total_postcard_duration, total_librum_duration));
}};
}
-#[derive(bzipper::Decode, bzipper::SizedEncode)]
+#[derive(librum::Decode, librum::Encode, librum::SizedEncode)]
#[derive(borsh::BorshSerialize)]
#[derive(serde::Deserialize, serde::Serialize)]
#[repr(transparent)]
struct Unit;
-#[derive(bzipper::Decode, bzipper::SizedEncode)]
+#[derive(librum::Decode, librum::Encode, librum::SizedEncode)]
#[derive(borsh::BorshSerialize)]
#[derive(serde::Deserialize, serde::Serialize)]
#[repr(transparent)]
@@ -112,13 +105,13 @@ impl Unnamed {
}
}
-#[derive(bzipper::Decode, bzipper::SizedEncode)]
+#[derive(librum::Decode, librum::Encode, librum::SizedEncode)]
#[derive(borsh::BorshSerialize)]
#[derive(serde::Deserialize, serde::Serialize)]
#[repr(transparent)]
struct Named { buf: [u8; 0x8] }
-#[derive(bzipper::Decode, bzipper::SizedEncode)]
+#[derive(librum::Decode, librum::Encode, librum::SizedEncode)]
#[derive(borsh::BorshSerialize)]
#[derive(serde::Deserialize, serde::Serialize)]
enum Enum {
@@ -147,16 +140,15 @@ impl Named {
}
fn main() {
- println!("######################");
- println!("# BZIPPER BENCHMARKS #");
- println!("######################");
+ println!("#####################");
+ println!("# LIBRUM BENCHMARKS #");
+ println!("#####################");
println!();
println!("Each benchmark has a version written for the following crates:");
println!();
println!("- Bincode: ");
println!("- Borsh: ");
- println!("- Ciborium: ");
- println!("- bzipper: ");
+ println!("- Librum: ");
println!("- Postcard: ");
println!();
println!("The total time the benchmark took (including memory allocations and dealloca-");
@@ -166,10 +158,10 @@ fn main() {
println!();
println!("When every benchmark has concluded, the total run time and vps is listed for");
println!("each crate. A percantage additionally compares the run time between the listed");
- println!("crate and bzipper (which should always be `0%` for bzipper itself). DO NOTE THAT");
- println!("THESE FINAL RESULTS INDICATE A NON-WEIGHTED AVERAGE ACROSS BENCHMARKS. It can");
- println!("therefore be skewed relative to real-world performance by the similarity of some");
- println!("benchmarks.");
+ println!("crate and librum (which should always be c. `0%` for Librum itself). DO NOTE");
+ println!("THAT THESE FINAL RESULTS INDICATE A NON-WEIGHTED AVERAGE ACROSS BENCHMARKS. It");
+ println!("can therefore be skewed relative to real-world performance by the similarity of");
+ println!("some benchmarks.");
println!();
eprintln!("value_count: {VALUE_COUNT}");
@@ -180,11 +172,10 @@ fn main() {
// Requires `std`.
use bincode::serialize_into;
- use std::io::Cursor;
- let buf_size = size_of::(); // value
+ let buf_size = size_of::();
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT]);
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
serialize_into(&mut buf, &random::()).unwrap();
@@ -192,21 +183,19 @@ fn main() {
}
borsh: {
- use std::io::Cursor;
+ let buf_size = size_of::();
- let buf_size = size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT]);
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
borsh::to_writer(&mut buf, &random::()).unwrap();
}
}
- bzipper: {
- use bzipper::{Encode, OStream, SizedEncode};
+ librum: {
+ use librum::{Encode, OStream, SizedEncode};
- let buf_size = u8::MAX_ENCODED_SIZE; // value
+ let buf_size = u8::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf);
@@ -216,26 +205,10 @@ fn main() {
}
}
- ciborium: {
- use std::io::Cursor;
-
- let buf_size =
- size_of::() // header
- + size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT]);
-
- for _ in 0x0..VALUE_COUNT {
- ciborium::into_writer(&random::(), &mut buf).unwrap();
- }
- }
-
postcard: {
- use std::io::Cursor;
+ let buf_size = size_of::();
- let buf_size = size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT]);
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
postcard::to_io(&random::(), &mut buf).unwrap();
@@ -243,14 +216,107 @@ fn main() {
}
}
+ encode_u32: {
+ bincode: {
+ use bincode::serialize_into;
+
+ let buf_size = size_of::();
+
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
+
+ for _ in 0x0..VALUE_COUNT {
+ serialize_into(&mut buf, &random::()).unwrap();
+ }
+ }
+
+ borsh: {
+ let buf_size = size_of::();
+
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
+
+ for _ in 0x0..VALUE_COUNT {
+ borsh::to_writer(&mut buf, &random::()).unwrap();
+ }
+ }
+
+ librum: {
+ use librum::{Encode, OStream, SizedEncode};
+
+ let buf_size = u32::MAX_ENCODED_SIZE;
+
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice();
+ let mut stream = OStream::new(&mut buf);
+
+ for _ in 0x0..VALUE_COUNT {
+ random::().encode(&mut stream).unwrap();
+ }
+ }
+
+ postcard: {
+ let buf_size = size_of::();
+
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
+
+ for _ in 0x0..VALUE_COUNT {
+ postcard::to_io(&random::(), &mut buf).unwrap();
+ }
+ }
+ }
+
+ encode_u128: {
+ bincode: {
+ use bincode::serialize_into;
+
+ let buf_size = size_of::();
+
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
+
+ for _ in 0x0..VALUE_COUNT {
+ serialize_into(&mut buf, &random::()).unwrap();
+ }
+ }
+
+ borsh: {
+ let buf_size = size_of::();
+
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
+
+ for _ in 0x0..VALUE_COUNT {
+ borsh::to_writer(&mut buf, &random::()).unwrap();
+ }
+ }
+
+ librum: {
+ use librum::{Encode, OStream, SizedEncode};
+
+ let buf_size = u128::MAX_ENCODED_SIZE;
+
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice();
+ let mut stream = OStream::new(&mut buf);
+
+ for _ in 0x0..VALUE_COUNT {
+ random::().encode(&mut stream).unwrap();
+ }
+ }
+
+ postcard: {
+ let buf_size = size_of::();
+
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
+
+ for _ in 0x0..VALUE_COUNT {
+ postcard::to_io(&random::(), &mut buf).unwrap();
+ }
+ }
+ }
+
encode_struct_unit: {
bincode: {
use bincode::serialize_into;
- use std::io::Cursor;
- let buf_size = size_of::(); // value
+ let buf_size = size_of::();
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT]);
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
serialize_into(&mut buf, &Unit).unwrap();
@@ -258,21 +324,19 @@ fn main() {
}
borsh: {
- use std::io::Cursor;
+ let buf_size = size_of::();
- let buf_size = size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
borsh::to_writer(&mut buf, &Unit).unwrap();
}
}
- bzipper: {
- use bzipper::{Encode, OStream, SizedEncode};
+ librum: {
+ use librum::{Encode, OStream, SizedEncode};
- let buf_size = Unit::MAX_ENCODED_SIZE; // value
+ let buf_size = Unit::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf);
@@ -282,26 +346,10 @@ fn main() {
}
}
- ciborium: {
- use std::io::Cursor;
-
- let buf_size =
- size_of::() // header
- + size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
-
- for _ in 0x0..VALUE_COUNT {
- ciborium::into_writer(&Unit, &mut buf).unwrap();
- }
- }
-
postcard: {
- use std::io::Cursor;
+ let buf_size = size_of::();
- let buf_size = size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
postcard::to_io(&Unit, &mut buf).unwrap();
@@ -312,11 +360,10 @@ fn main() {
encode_struct_unnamed: {
bincode: {
use bincode::serialize_into;
- use std::io::Cursor;
- let buf_size = size_of::(); // value
+ let buf_size = size_of::();
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT]);
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
serialize_into(&mut buf, &Unnamed::from_char(random())).unwrap();
@@ -324,21 +371,19 @@ fn main() {
}
borsh: {
- use std::io::Cursor;
+ let buf_size = size_of::();
- let buf_size = size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
borsh::to_writer(&mut buf, &Unnamed::from_char(random())).unwrap();
}
}
- bzipper: {
- use bzipper::{Encode, OStream, SizedEncode};
+ librum: {
+ use librum::{Encode, OStream, SizedEncode};
- let buf_size = Unnamed::MAX_ENCODED_SIZE; // value
+ let buf_size = Unnamed::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf);
@@ -348,26 +393,10 @@ fn main() {
}
}
- ciborium: {
- use std::io::Cursor;
-
- let buf_size =
- size_of::() // header
- + size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
-
- for _ in 0x0..VALUE_COUNT {
- ciborium::into_writer(&Unnamed::from_char(random()), &mut buf).unwrap();
- }
- }
-
postcard: {
- use std::io::Cursor;
+ let buf_size = size_of::();
- let buf_size = size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
postcard::to_io(&Unnamed::from_char(random()), &mut buf).unwrap();
@@ -378,11 +407,10 @@ fn main() {
encode_struct_named: {
bincode: {
use bincode::serialize_into;
- use std::io::Cursor;
- let buf_size = size_of::(); // value
+ let buf_size = size_of::();
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT]);
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
serialize_into(&mut buf, &Named::from_u64(random())).unwrap();
@@ -390,21 +418,19 @@ fn main() {
}
borsh: {
- use std::io::Cursor;
+ let buf_size = size_of::();
- let buf_size = size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
borsh::to_writer(&mut buf, &Named::from_u64(random())).unwrap();
}
}
- bzipper: {
- use bzipper::{Encode, OStream, SizedEncode};
+ librum: {
+ use librum::{Encode, OStream, SizedEncode};
- let buf_size = Named::MAX_ENCODED_SIZE; // value
+ let buf_size = Named::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf);
@@ -414,28 +440,10 @@ fn main() {
}
}
- ciborium: {
- use std::io::Cursor;
-
- let buf_size =
- size_of::() // header
- + size_of::() // tag
- + size_of::() // header
- + size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
-
- for _ in 0x0..VALUE_COUNT {
- ciborium::into_writer(&Named::from_u64(random()), &mut buf).unwrap();
- }
- }
-
postcard: {
- use std::io::Cursor;
+ let buf_size = size_of::();
- let buf_size = size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
postcard::to_io(&Named::from_u64(random()), &mut buf).unwrap();
@@ -446,13 +454,12 @@ fn main() {
encode_enum_unit: {
bincode: {
use bincode::serialize_into;
- use std::io::Cursor;
let buf_size =
- size_of::() // discriminant
- + size_of::(); // value
+ size_of::() // discriminant
+ + size_of::();
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT]);
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
serialize_into(&mut buf, &Enum::Unit(Unit)).unwrap();
@@ -460,25 +467,23 @@ fn main() {
}
borsh: {
- use std::io::Cursor;
-
let buf_size =
- size_of::() // discriminant
- + size_of::(); // value
+ size_of::() // discriminant
+ + size_of::();
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
borsh::to_writer(&mut buf, &Enum::Unit(Unit)).unwrap();
}
}
- bzipper: {
- use bzipper::{Encode, OStream, SizedEncode};
+ librum: {
+ use librum::{Encode, OStream, SizedEncode};
let buf_size =
- isize::MAX_ENCODED_SIZE // discriminant
- + Unit::MAX_ENCODED_SIZE; // value
+ isize::MAX_ENCODED_SIZE // discriminant
+ + Unit::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf);
@@ -488,30 +493,12 @@ fn main() {
}
}
- ciborium: {
- use std::io::Cursor;
-
- let buf_size =
- size_of::() // header
- + size_of::() // tag (discriminant)
- + size_of::() // header
- + size_of::(); // value
-
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
-
- for _ in 0x0..VALUE_COUNT {
- ciborium::into_writer(&Enum::Unit(Unit), &mut buf).unwrap();
- }
- }
-
postcard: {
- use std::io::Cursor;
-
let buf_size =
- size_of::() // discriminant
- + size_of::(); // value
+ size_of::() // discriminant
+ + size_of::();
- let mut buf = Cursor::new(vec![0x00; buf_size * VALUE_COUNT].into_boxed_slice());
+ let mut buf = vec![0x00; buf_size * VALUE_COUNT];
for _ in 0x0..VALUE_COUNT {
postcard::to_io(&Enum::Unit(Unit), &mut buf).unwrap();
diff --git a/bzipper_macros/Cargo.toml b/librum-macros/Cargo.toml
similarity index 78%
rename from bzipper_macros/Cargo.toml
rename to librum-macros/Cargo.toml
index 1904763..cef6b99 100644
--- a/bzipper_macros/Cargo.toml
+++ b/librum-macros/Cargo.toml
@@ -1,8 +1,8 @@
[package]
-name = "bzipper_macros"
-version = "0.11.0"
+name = "librum-macros"
+version = "0.12.0"
edition = "2021"
-documentation = "https://docs.rs/bzipper_macros/"
+documentation = "https://docs.rs/librum-macros/"
authors.workspace = true
description.workspace = true
diff --git a/bzipper_macros/src/discriminant_iter/mod.rs b/librum-macros/src/discriminants/mod.rs
similarity index 50%
rename from bzipper_macros/src/discriminant_iter/mod.rs
rename to librum-macros/src/discriminants/mod.rs
index ea34f6d..b3883f4 100644
--- a/bzipper_macros/src/discriminant_iter/mod.rs
+++ b/librum-macros/src/discriminants/mod.rs
@@ -1,35 +1,34 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
-// This file is part of bZipper.
+// This file is part of Librum.
//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
// Lesser General Public License as published by
// the Free Software Foundation, either version 3
// of the License, or (at your option) any later
// version.
//
-// bZipper is distributed in the hope that it will
+// Librum is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
+// er General Public License along with Librum. If
// not, see .
-use crate::Discriminant;
-
use std::borrow::Borrow;
-use syn::Variant;
+use proc_macro2::Span;
+use syn::{Expr, Lit, LitInt, Variant};
-pub struct DiscriminantIter>> {
+pub struct Discriminants>> {
variants: I::IntoIter,
- prev: Option,
+ prev: Option,
}
-impl>> DiscriminantIter {
+impl>> Discriminants {
#[inline(always)]
#[must_use]
pub fn new(variants: I) -> Self {
@@ -40,28 +39,43 @@ impl>> DiscriminantIter {
}
}
-impl>> Iterator for DiscriminantIter {
- type Item = (Discriminant, I::Item);
+impl>> Iterator for Discriminants {
+ type Item = LitInt;
#[inline]
fn next(&mut self) -> Option {
let variant = self.variants.next()?;
- let discriminant = if let Some((_, ref discriminant)) = variant.borrow().discriminant {
- Discriminant::parse(discriminant)
- } else if let Some(discriminant) = self.prev {
- let value = discriminant.0
- .checked_add(0x1)
- .unwrap_or_else(|| panic!("overflow following discriminant `{discriminant:?}`"));
+ let discriminant = if let Some((_, ref expr)) = variant.borrow().discriminant {
+ let Expr::Lit(ref expr) = *expr else {
+ panic!("expected literal expression for discriminant value");
+ };
- Discriminant(value)
+ let Lit::Int(ref expr) = expr.lit else {
+ panic!("expected (potentially signed) integer literal for discriminant value`");
+ };
+
+ let expr = expr.base10_digits();
+
+ let value: u128 = expr
+ .parse()
+ .or_else(|_| expr.parse::().map(|v| v as u128))
+ .unwrap();
+
+ value
+ } else if let Some(prev) = self.prev {
+ prev
+ .checked_add(0x1)
+ .unwrap_or_else(|| panic!("overflow following discriminant `{prev:?}`"))
} else {
Default::default()
};
self.prev = Some(discriminant);
- Some((discriminant, variant))
+ let discriminant = LitInt::new(&discriminant.to_string(), Span::call_site());
+
+ Some(discriminant)
}
#[inline(always)]
diff --git a/bzipper_macros/src/generic_name/mod.rs b/librum-macros/src/generic_name/mod.rs
similarity index 89%
rename from bzipper_macros/src/generic_name/mod.rs
rename to librum-macros/src/generic_name/mod.rs
index 6fc0bc9..d9a372a 100644
--- a/bzipper_macros/src/generic_name/mod.rs
+++ b/librum-macros/src/generic_name/mod.rs
@@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
-// This file is part of bZipper.
+// This file is part of Librum.
//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
// Lesser General Public License as published by
// the Free Software Foundation, either version 3
// of the License, or (at your option) any later
// version.
//
-// bZipper is distributed in the hope that it will
+// Librum is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
+// er General Public License along with Librum. If
// not, see .
use proc_macro2::TokenStream;
diff --git a/librum-macros/src/impl_derive_macro.rs b/librum-macros/src/impl_derive_macro.rs
new file mode 100644
index 0000000..3c6f025
--- /dev/null
+++ b/librum-macros/src/impl_derive_macro.rs
@@ -0,0 +1,80 @@
+// Copyright 2024 Gabriel Bjørnager Jensen.
+//
+// This file is part of Librum.
+//
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
+// Lesser General Public License as published by
+// the Free Software Foundation, either version 3
+// of the License, or (at your option) any later
+// version.
+//
+// Librum is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without
+// even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Less-
+// er General Public License along with Librum. If
+// not, see .
+
+use crate::{GenericName, Repr};
+
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{
+ Data,
+ DataEnum,
+ DataStruct,
+ DeriveInput,
+ Path,
+ Token,
+};
+
+pub fn impl_derive_macro(
+ input: DeriveInput,
+ trait_path: Path,
+ r#unsafe_token: Option,
+ struct_body: S,
+ enum_body: E,
+) -> TokenStream
+where
+ S: FnOnce(DataStruct) -> TokenStream,
+ E: FnOnce(DataEnum, Repr) -> TokenStream,
+{
+ let trait_name = &trait_path
+ .segments
+ .last()
+ .expect("expected non-empty path for derived trait")
+ .ident;
+
+ let self_name = &input.ident;
+
+ let body = match input.data {
+ Data::Struct(data) => struct_body(data),
+
+ Data::Enum(data) => {
+ let repr = Repr::get(&input.attrs).unwrap_or_default();
+
+ enum_body(data, repr)
+ }
+
+ Data::Union(..) => panic!("unions cannot derive `{trait_name:?}`"),
+ };
+
+ let generic_params = &input.generics.params;
+ let generic_where = &input.generics.where_clause;
+
+ let generic_names = GenericName::extract_from(&input.generics);
+
+ let output = quote! {
+ #unsafe_token impl<#generic_params> #trait_path for #self_name<#generic_names>
+ #generic_where
+ {
+ #body
+ }
+ };
+
+ output
+}
\ No newline at end of file
diff --git a/librum-macros/src/impls/decode_enum.rs b/librum-macros/src/impls/decode_enum.rs
new file mode 100644
index 0000000..3da3a38
--- /dev/null
+++ b/librum-macros/src/impls/decode_enum.rs
@@ -0,0 +1,82 @@
+// Copyright 2024 Gabriel Bjørnager Jensen.
+//
+// This file is part of Librum.
+//
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
+// Lesser General Public License as published by
+// the Free Software Foundation, either version 3
+// of the License, or (at your option) any later
+// version.
+//
+// Librum is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without
+// even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Less-
+// er General Public License along with Librum. If
+// not, see .
+
+use crate::{Discriminants, Repr};
+
+use proc_macro2::TokenStream;
+use quote::quote;
+use std::iter;
+use syn::{DataEnum, Fields};
+
+#[must_use]
+pub fn decode_enum(data: DataEnum, repr: Repr) -> TokenStream {
+ let discriminants: Vec<_> = Discriminants::new(&data.variants).collect();
+
+ let values = data
+ .variants
+ .into_iter()
+ .map(|variant| {
+ let variant_name = variant.ident;
+
+ let commands = iter::repeat_n(
+ quote! {
+ ::librum::Decode::decode(stream)
+ .map_err(::core::convert::Into::<::librum::error::GenericDecodeError>::into)
+ .map_err(::librum::error::EnumDecodeError::Field)?
+ },
+ variant.fields.len(),
+ );
+
+ match variant.fields {
+ Fields::Unit => quote! { Self::#variant_name },
+
+ Fields::Unnamed(_fields) => quote! { Self::#variant_name (#(#commands, )*) },
+
+ Fields::Named(fields) => {
+ let field_names = fields
+ .named
+ .into_iter()
+ .map(|field| field.ident.unwrap());
+
+ quote! { Self::#variant_name { #(#field_names: #commands, )* } }
+ },
+ }
+ });
+
+ quote! {
+ type Error = ::librum::error::EnumDecodeError<#repr, ::librum::error::GenericDecodeError>;
+
+ #[inline]
+ fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result {
+ let discriminant = <#repr as ::librum::Decode>::decode(stream)
+ .map_err(::core::convert::Into::<::core::convert::Infallible>::into)
+ .map_err(::librum::error::EnumDecodeError::InvalidDiscriminant)?;
+
+ let this = match discriminant {
+ #(#discriminants => #values,)*
+
+ value => return ::core::result::Result::Err(::librum::error::EnumDecodeError::UnassignedDiscriminant { value }),
+ };
+
+ ::core::result::Result::Ok(this)
+ }
+ }
+}
diff --git a/librum-macros/src/impls/decode_struct.rs b/librum-macros/src/impls/decode_struct.rs
new file mode 100644
index 0000000..0270c7c
--- /dev/null
+++ b/librum-macros/src/impls/decode_struct.rs
@@ -0,0 +1,61 @@
+// Copyright 2024 Gabriel Bjørnager Jensen.
+//
+// This file is part of Librum.
+//
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
+// Lesser General Public License as published by
+// the Free Software Foundation, either version 3
+// of the License, or (at your option) any later
+// version.
+//
+// Librum is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without
+// even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Less-
+// er General Public License along with Librum. If
+// not, see .
+
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{DataStruct, Fields};
+use std::iter;
+
+#[must_use]
+pub fn decode_struct(data: DataStruct) -> TokenStream {
+ let commands = iter::repeat_n(
+ quote! {
+ ::librum::Decode::decode(stream)
+ .map_err(::core::convert::Into::<::librum::error::GenericDecodeError>::into)?
+ },
+ data.fields.len(),
+ );
+
+ let value = match data.fields {
+ Fields::Unit => quote! { Self },
+
+ Fields::Unnamed(_fields) => quote! { Self (#(#commands, )*) },
+
+ Fields::Named(fields) => {
+ let field_names = fields
+ .named
+ .into_iter()
+ .map(|field| field.ident.unwrap());
+
+ quote! { Self { #(#field_names: #commands, )* } }
+ },
+ };
+
+ quote! {
+ type Error = ::librum::error::GenericDecodeError;
+
+ #[inline]
+ fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result {
+ let this = #value;
+ ::core::result::Result::Ok(this)
+ }
+ }
+}
diff --git a/librum-macros/src/impls/encode_enum.rs b/librum-macros/src/impls/encode_enum.rs
new file mode 100644
index 0000000..19c949d
--- /dev/null
+++ b/librum-macros/src/impls/encode_enum.rs
@@ -0,0 +1,94 @@
+// Copyright 2024 Gabriel Bjørnager Jensen.
+//
+// This file is part of Librum.
+//
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
+// Lesser General Public License as published by
+// the Free Software Foundation, either version 3
+// of the License, or (at your option) any later
+// version.
+//
+// Librum is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without
+// even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Less-
+// er General Public License along with Librum. If
+// not, see .
+
+use crate::{Discriminants, Repr};
+
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use syn::{DataEnum, Fields, Ident, LitInt};
+
+#[must_use]
+pub fn encode_enum(data: DataEnum, repr: Repr) -> TokenStream {
+ let discriminants: Vec = Discriminants::new(&data.variants).collect();
+
+ let captures: Vec> = data
+ .variants
+ .iter()
+ .map(|variant| {
+ variant
+ .fields
+ .iter()
+ .enumerate()
+ .map(|(index, _)| Ident::new(&format!("value{index}"), Span::call_site()))
+ .collect()
+ })
+ .collect();
+
+ let patterns = data
+ .variants
+ .into_iter()
+ .zip(&captures)
+ .map(|(variant, captures)| {
+ let variant_name = variant.ident;
+
+ match variant.fields {
+ Fields::Unit => quote! { Self::#variant_name },
+
+ Fields::Unnamed(_fields) => quote! { Self::#variant_name (#(ref #captures, )*) },
+
+ Fields::Named(fields) => {
+ let field_names = fields
+ .named
+ .into_iter()
+ .map(|field| field.ident.unwrap());
+
+ quote! { Self::#variant_name { #(#field_names: ref #captures, )* } }
+ },
+ }
+ });
+
+ quote! {
+ type Error = ::librum::error::EnumEncodeError<#repr, ::librum::error::GenericEncodeError>;
+
+ #[allow(unreachable_patterns)]
+ #[inline]
+ fn encode(&self, stream: &mut ::librum::OStream) -> ::core::result::Result<(), Self::Error> {
+ match *self {
+ #(
+ #patterns => {
+ <#repr as ::librum::Encode>::encode(discriminants, stream)
+ .map_err(::librum::error::EnumEncodeError::Discriminant)?;
+
+ #(
+ ::librum::Encode::encode(#captures, stream)
+ .map_err(::core::convert::Into::<::librum::error::GenericEncodeError>::into)
+ .map_err(::librum::error::EnumEncodeError::Field)?;
+ )*
+ }
+ )*
+
+ _ => ::core::unreachable!("no variants defined for this enumeration"),
+ }
+
+ ::core::result::Result::Ok(())
+ }
+ }
+}
diff --git a/librum-macros/src/impls/encode_struct.rs b/librum-macros/src/impls/encode_struct.rs
new file mode 100644
index 0000000..da37fbc
--- /dev/null
+++ b/librum-macros/src/impls/encode_struct.rs
@@ -0,0 +1,65 @@
+// Copyright 2024 Gabriel Bjørnager Jensen.
+//
+// This file is part of Librum.
+//
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
+// Lesser General Public License as published by
+// the Free Software Foundation, either version 3
+// of the License, or (at your option) any later
+// version.
+//
+// Librum is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without
+// even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Less-
+// er General Public License along with Librum. If
+// not, see .
+
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use syn::{DataStruct, Fields, Ident};
+
+#[must_use]
+pub fn encode_struct(data: DataStruct) -> TokenStream {
+ let captures: Vec<_> = data
+ .fields
+ .iter()
+ .enumerate()
+ .map(|(index, _)| Ident::new(&format!("value{index}"), Span::call_site()))
+ .collect();
+
+ let pattern = match data.fields {
+ Fields::Unit => quote! { Self },
+
+ Fields::Unnamed(_fields) => quote! { Self(#(ref #captures, )*) },
+
+ Fields::Named(fields) => {
+ let field_names = fields
+ .named
+ .into_iter()
+ .map(|field| field.ident.unwrap());
+
+ quote! { Self { #(#field_names: ref #captures, )* } }
+ },
+ };
+
+ quote! {
+ type Error = ::librum::error::GenericEncodeError;
+
+ #[inline]
+ fn encode(&self, stream: &mut ::librum::OStream) -> ::core::result::Result<(), Self::Error> {
+ let #pattern = self;
+
+ #(
+ ::librum::Encode::encode(#captures, stream)
+ .map_err(::core::convert::Into::<::librum::error::GenericEncodeError>::into)?;
+ )*
+
+ ::core::result::Result::Ok(())
+ }
+ }
+}
diff --git a/bzipper_macros/src/impls/mod.rs b/librum-macros/src/impls/mod.rs
similarity index 75%
rename from bzipper_macros/src/impls/mod.rs
rename to librum-macros/src/impls/mod.rs
index cdbc9ac..c272ca6 100644
--- a/bzipper_macros/src/impls/mod.rs
+++ b/librum-macros/src/impls/mod.rs
@@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
-// This file is part of bZipper.
+// This file is part of Librum.
//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
// Lesser General Public License as published by
// the Free Software Foundation, either version 3
// of the License, or (at your option) any later
// version.
//
-// bZipper is distributed in the hope that it will
+// Librum is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
+// er General Public License along with Librum. If
// not, see .
use crate::use_mod;
diff --git a/librum-macros/src/impls/sized_encode_enum.rs b/librum-macros/src/impls/sized_encode_enum.rs
new file mode 100644
index 0000000..23ddd15
--- /dev/null
+++ b/librum-macros/src/impls/sized_encode_enum.rs
@@ -0,0 +1,59 @@
+// Copyright 2024 Gabriel Bjørnager Jensen.
+//
+// This file is part of Librum.
+//
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
+// Lesser General Public License as published by
+// the Free Software Foundation, either version 3
+// of the License, or (at your option) any later
+// version.
+//
+// Librum is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without
+// even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Less-
+// er General Public License along with Librum. If
+// not, see .
+
+use crate::Repr;
+
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use std::iter;
+use syn::DataEnum;
+
+#[must_use]
+pub fn sized_encode_enum(data: DataEnum, repr: Repr) -> TokenStream {
+ let tys: Vec> = data
+ .variants
+ .iter()
+ .map(|variant| {
+ variant
+ .fields
+ .iter()
+ .map(|field| field.ty.clone())
+ .chain(iter::once(repr.to_type(Span::call_site())))
+ .collect()
+ })
+ .collect();
+
+ quote! {
+ const MAX_ENCODED_SIZE: usize = {
+ let mut total_size = 0x0usize;
+
+ let mut current_size = 0x0usize;
+
+ #(
+ current_size = 0x0 #(+ <#tys as ::librum::SizedEncode>::MAX_ENCODED_SIZE)*;
+
+ if current_size > total_size { total_size = current_size };
+ )*
+
+ total_size
+ };
+ }
+}
diff --git a/bzipper_macros/src/impls/sized_encode_struct.rs b/librum-macros/src/impls/sized_encode_struct.rs
similarity index 55%
rename from bzipper_macros/src/impls/sized_encode_struct.rs
rename to librum-macros/src/impls/sized_encode_struct.rs
index e194e08..95ddd52 100644
--- a/bzipper_macros/src/impls/sized_encode_struct.rs
+++ b/librum-macros/src/impls/sized_encode_struct.rs
@@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
-// This file is part of bZipper.
+// This file is part of Librum.
//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
// Lesser General Public License as published by
// the Free Software Foundation, either version 3
// of the License, or (at your option) any later
// version.
//
-// bZipper is distributed in the hope that it will
+// Librum is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
+// er General Public License along with Librum. If
// not, see .
use proc_macro2::TokenStream;
@@ -24,14 +24,13 @@ use quote::quote;
use syn::DataStruct;
#[must_use]
-pub fn sized_encode_struct(data: &DataStruct) -> TokenStream {
- let mut field_tys = Vec::new();
-
- for field in &data.fields {
- field_tys.push(&field.ty);
- }
+pub fn sized_encode_struct(data: DataStruct) -> TokenStream {
+ let tys: Vec<_> = data.fields
+ .into_iter()
+ .map(|field| field.ty)
+ .collect();
quote! {
- const MAX_ENCODED_SIZE: usize = 0x0 #( + <#field_tys as ::bzipper::SizedEncode>::MAX_ENCODED_SIZE)*;
+ const MAX_ENCODED_SIZE: usize = 0x0 #( + <#tys as ::librum::SizedEncode>::MAX_ENCODED_SIZE)*;
}
}
diff --git a/librum-macros/src/lib.rs b/librum-macros/src/lib.rs
new file mode 100644
index 0000000..2097b1c
--- /dev/null
+++ b/librum-macros/src/lib.rs
@@ -0,0 +1,97 @@
+// Copyright 2024 Gabriel Bjørnager Jensen.
+//
+// This file is part of Librum.
+//
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
+// Lesser General Public License as published by
+// the Free Software Foundation, either version 3
+// of the License, or (at your option) any later
+// version.
+//
+// Librum is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without
+// even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Less-
+// er General Public License along with Librum. If
+// not, see .
+
+#![doc(html_logo_url = "https://gitlab.com/bjoernager/librum/-/raw/master/doc-icon.svg")]
+
+//! This crate implements procedural macros for [`Librum`](https://crates.io/crates/librum/).
+
+// For use in macros:
+extern crate self as librum_macros;
+
+macro_rules! use_mod {
+ ($vis:vis $name:ident) => {
+ mod $name;
+ $vis use $name::*;
+ };
+}
+pub(crate) use use_mod;
+
+use_mod!(discriminants);
+use_mod!(generic_name);
+use_mod!(impl_derive_macro);
+use_mod!(repr);
+
+mod impls;
+
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::{DeriveInput, parse2};
+
+#[proc_macro_derive(Decode)]
+pub fn derive_decode(input: TokenStream) -> TokenStream {
+ let input = syn::parse_macro_input!(input as DeriveInput);
+
+ let output = impl_derive_macro(
+ input,
+ parse2(quote! { ::librum::Decode }).unwrap(),
+ None,
+ impls::decode_struct,
+ impls::decode_enum,
+ );
+
+ //panic!("{output}");
+
+ output.into()
+}
+
+#[proc_macro_derive(Encode)]
+pub fn derive_encode(input: TokenStream) -> TokenStream {
+ let input = syn::parse_macro_input!(input as DeriveInput);
+
+ let output = impl_derive_macro(
+ input,
+ parse2(quote! { ::librum::Encode }).unwrap(),
+ None,
+ impls::encode_struct,
+ impls::encode_enum,
+ );
+
+ //panic!("{output}");
+
+ output.into()
+}
+
+#[proc_macro_derive(SizedEncode)]
+pub fn derive_sized_encode(input: TokenStream) -> TokenStream {
+ let input = syn::parse_macro_input!(input as DeriveInput);
+
+ let output = impl_derive_macro(
+ input,
+ parse2(quote! { ::librum::SizedEncode }).unwrap(),
+ None,
+ impls::sized_encode_struct,
+ impls::sized_encode_enum,
+ );
+
+ //panic!("{output}");
+
+ output.into()
+}
diff --git a/librum-macros/src/repr/mod.rs b/librum-macros/src/repr/mod.rs
new file mode 100644
index 0000000..e87f8c5
--- /dev/null
+++ b/librum-macros/src/repr/mod.rs
@@ -0,0 +1,157 @@
+// Copyright 2024 Gabriel Bjørnager Jensen.
+//
+// This file is part of Librum.
+//
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
+// Lesser General Public License as published by
+// the Free Software Foundation, either version 3
+// of the License, or (at your option) any later
+// version.
+//
+// Librum is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without
+// even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Less-
+// er General Public License along with Librum. If
+// not, see .
+
+use proc_macro2::{Span, TokenStream};
+use quote::ToTokens;
+use std::iter;
+use syn::{
+ Attribute,
+ Ident,
+ Path,
+ PathSegment,
+ Type,
+ TypePath,
+};
+
+/// A derivable enumeration representation.
+///
+/// Any type can, *in theory*, be used as a discriminant.
+/// This type, however, only includes primitives.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[repr(u8)]
+pub enum Repr {
+ U8,
+ I8,
+ U16,
+ I16,
+ U32,
+ I32,
+ U64,
+ I64,
+ U128,
+ I128,
+ Usize,
+ Isize,
+}
+
+impl Repr {
+ #[inline]
+ #[must_use]
+ pub fn get(attrs: &[Attribute]) -> Option {
+ let mut this = None;
+
+ for attr in attrs {
+ if attr.path().is_ident("repr") {
+ attr.parse_nested_meta(|meta| {
+ use Repr::*;
+
+ let ident = meta.path.require_ident()?;
+
+ if ident == "u8" { this = Some(U8) }
+ else if ident == "i8" { this = Some(I8) }
+ else if ident == "u16" { this = Some(U16) }
+ else if ident == "i16" { this = Some(I16) }
+ else if ident == "u32" { this = Some(U32) }
+ else if ident == "i32" { this = Some(I32) }
+ else if ident == "u64" { this = Some(U64) }
+ else if ident == "i64" { this = Some(I64) }
+ else if ident == "u128" { this = Some(U128) }
+ else if ident == "i128" { this = Some(I128) }
+ else if ident == "usize" { this = Some(Usize) }
+ else if ident == "isize" { this = Some(Isize) }
+ else { panic!("`{ident}` is not a derivable enumeration representation") };
+
+ Ok(())
+ }).unwrap();
+ }
+
+ // Ignore all other attributes.
+ }
+
+ this
+ }
+
+ #[inline]
+ #[must_use]
+ pub const fn to_str(self) -> &'static str {
+ use Repr::*;
+
+ match self {
+ U8 => "u8",
+ I8 => "i8",
+ U16 => "u16",
+ I16 => "i16",
+ U32 => "u32",
+ I32 => "i32",
+ U64 => "u64",
+ I64 => "i64",
+ U128 => "u128",
+ I128 => "i128",
+ Usize => "usize",
+ Isize => "isize",
+ }
+ }
+
+ #[inline(always)]
+ #[must_use]
+ pub fn to_ident(self, span: Span) -> Ident {
+ let ident = self.to_str();
+
+ Ident::new(ident, span)
+ }
+
+ #[inline(always)]
+ #[must_use]
+ pub fn to_path(self, span: Span) -> Path {
+ let ident = self.to_ident(span);
+
+ Path {
+ leading_colon: None,
+ segments: iter::once(PathSegment {
+ ident,
+ arguments: Default::default(),
+ }).collect(),
+ }
+ }
+
+ #[inline]
+ #[must_use]
+ pub fn to_type(self, span: Span) -> Type {
+ Type::Path(TypePath {
+ qself: None,
+ path: self.to_path(span),
+ })
+ }
+}
+
+impl Default for Repr {
+ #[inline(always)]
+ fn default() -> Self {
+ Self::Isize
+ }
+}
+
+impl ToTokens for Repr {
+ #[inline(always)]
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.to_ident(Span::call_site()).to_tokens(tokens);
+ }
+}
diff --git a/bzipper.svg b/librum.svg
similarity index 100%
rename from bzipper.svg
rename to librum.svg
diff --git a/bzipper/Cargo.toml b/librum/Cargo.toml
similarity index 58%
rename from bzipper/Cargo.toml
rename to librum/Cargo.toml
index 5912aa5..687a206 100644
--- a/bzipper/Cargo.toml
+++ b/librum/Cargo.toml
@@ -1,9 +1,9 @@
[package]
-name = "bzipper"
-version = "0.11.0"
+name = "librum"
+version = "0.12.0"
edition = "2021"
rust-version = "1.83"
-documentation = "https://docs.rs/bzipper/"
+documentation = "https://docs.rs/librum/"
authors.workspace = true
description.workspace = true
@@ -18,13 +18,14 @@ categories.workspace = true
all-features = true
[features]
-default = ["alloc", "std"]
+default = ["alloc", "proc-macro", "std"]
-alloc = []
-std = []
+alloc = []
+proc-macro = ["librum-macros"]
+std = []
[dependencies]
-bzipper_macros = { path = "../bzipper_macros", version = "0.11.0" }
+librum-macros = { path = "../librum-macros", version = "0.12.0", optional = true}
[lints]
workspace = true
diff --git a/bzipper/src/buf/mod.rs b/librum/src/buf/mod.rs
similarity index 93%
rename from bzipper/src/buf/mod.rs
rename to librum/src/buf/mod.rs
index d567760..f788917 100644
--- a/bzipper/src/buf/mod.rs
+++ b/librum/src/buf/mod.rs
@@ -1,26 +1,26 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
-// This file is part of bZipper.
+// This file is part of Librum.
//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
// Lesser General Public License as published by
// the Free Software Foundation, either version 3
// of the License, or (at your option) any later
// version.
//
-// bZipper is distributed in the hope that it will
+// Librum is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
+// er General Public License along with Librum. If
// not, see .
#[cfg(test)]
-mod test;
+mod tests;
use crate::{
Decode,
@@ -29,7 +29,6 @@ use crate::{
OStream,
SizedEncode,
};
-use crate::error::{DecodeError, EncodeError};
use alloc::boxed::Box;
use alloc::vec;
@@ -52,9 +51,15 @@ use core::slice::{self, SliceIndex};
/// Create a buffer for holding a `Request` enumeration:
///
/// ```
-/// use bzipper::{Buf, SizedEncode, SizedStr};
+/// use librum::{
+/// Buf,
+/// Encode,
+/// OStream,
+/// SizedEncode,
+/// SizedStr,
+/// };
///
-/// #[derive(SizedEncode)]
+/// #[derive(Debug, Encode, SizedEncode)]
/// enum Request {
/// Join { username: SizedStr<0x40> },
///
@@ -264,13 +269,13 @@ impl Buf {
impl Buf {
/// Encodes an object into the buffer.
///
- /// The object is encoded as by being passed to ::[encode](Encode::encode)
.
+ /// The object is encoded as by being passed to <T as [Encode]>::[encode](Encode::encode)
.
///
/// # Errors
///
/// Any error that occurs during encoding is passed on and returned from this method.
#[inline]
- pub fn write>(&mut self, value: U) -> Result<(), EncodeError> {
+ pub fn write>(&mut self, value: U) -> Result<(), T::Error> {
let mut stream = OStream::new(&mut self.buf);
value.borrow().encode(&mut stream)?;
@@ -285,7 +290,7 @@ impl Buf {
impl Buf {
/// Decodes an object from the buffer.
///
- /// This is done as by passing the contained bytes to ::[decode](Decode::decode)
.
+ /// This is done as by passing the contained bytes to <T as [Decode]>::[decode](Decode::decode)
.
///
/// Note that only the bytes specified by [`len`](Self::len) are passed in this call.
/// See [`as_slice`](Self::as_slice) for more information.
@@ -294,7 +299,7 @@ impl Buf {
///
/// Any error that occurs during decoding is passed on and returned from this method.
#[inline]
- pub fn read(&self) -> Result {
+ pub fn read(&self) -> Result {
// We should only pass the used part of the buffer
// to `deserialise`.
diff --git a/bzipper/src/buf/test.rs b/librum/src/buf/tests.rs
similarity index 74%
rename from bzipper/src/buf/test.rs
rename to librum/src/buf/tests.rs
index eec22df..ebf6764 100644
--- a/bzipper/src/buf/test.rs
+++ b/librum/src/buf/tests.rs
@@ -1,26 +1,26 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
-// This file is part of bZipper.
+// This file is part of Librum.
//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
// Lesser General Public License as published by
// the Free Software Foundation, either version 3
// of the License, or (at your option) any later
// version.
//
-// bZipper is distributed in the hope that it will
+// Librum is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
+// er General Public License along with Librum. If
// not, see .
-use bzipper::Buf;
-use bzipper::error::DecodeError;
+use librum::Buf;
+use librum::error::CharDecodeError;
#[test]
fn test_buf_write_read() {
@@ -40,7 +40,7 @@ fn test_buf_write_read() {
assert_eq!(buf, [0x00, 0x01, 0xF4, 0x4D].as_slice());
buf.copy_from_slice(&[0x00, 0x00, 0xD8, 0x00]);
- test_read!(Err(DecodeError::InvalidCodePoint(0xD800)));
+ test_read!(Err(CharDecodeError { code_point: 0xD800 }));
buf.copy_from_slice(&[0x00, 0x00, 0xFF, 0x3A]);
test_read!(Ok('\u{FF3A}'));
diff --git a/bzipper/src/decode/mod.rs b/librum/src/decode/mod.rs
similarity index 56%
rename from bzipper/src/decode/mod.rs
rename to librum/src/decode/mod.rs
index b7ca717..e74be08 100644
--- a/bzipper/src/decode/mod.rs
+++ b/librum/src/decode/mod.rs
@@ -1,29 +1,38 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
-// This file is part of bZipper.
+// This file is part of Librum.
//
-// bZipper is free software: you can redistribute
-// it and/or modify it under the terms of the GNU
+// Librum is free software: you can redistribute it
+// and/or modify it under the terms of the GNU
// Lesser General Public License as published by
// the Free Software Foundation, either version 3
// of the License, or (at your option) any later
// version.
//
-// bZipper is distributed in the hope that it will
+// Librum is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Less-
-// er General Public License along with bZipper. If
+// er General Public License along with Librum. If
// not, see .
#[cfg(test)]
-mod test;
+mod tests;
-use crate::{IStream, SizedEncode};
-use crate::error::{DecodeError, Utf8Error};
+use crate::{DecodeBorrowed, IStream, SizedEncode};
+use crate::error::{
+ BoolDecodeError,
+ CStringDecodeError,
+ CharDecodeError,
+ CollectionDecodeError,
+ EnumDecodeError,
+ ItemDecodeError,
+ SystemTimeDecodeError,
+ Utf8Error,
+};
use core::cell::{Cell, RefCell};
use core::convert::Infallible;
@@ -52,6 +61,9 @@ use core::ptr::copy_nonoverlapping;
use core::str;
use core::time::Duration;
+#[cfg(feature = "alloc")]
+use alloc::borrow::{Cow, ToOwned};
+
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
@@ -70,7 +82,7 @@ use alloc::vec::Vec;
#[cfg(feature = "alloc")]
use alloc::rc::Rc;
-#[cfg(feature = "alloc")]
+#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
use alloc::sync::Arc;
#[cfg(feature = "std")]
@@ -89,41 +101,47 @@ use std::time::{SystemTime, UNIX_EPOCH};
/// Denotes a type capable of being decoded.
pub trait Decode: Sized {
+ type Error;
+
/// Decodes an object from the provided stream.
///
/// # Errors
///
/// If decoding fails due to e.g. an invalid byte sequence in the stream, then an error should be returned.
- fn decode(stream: &mut IStream) -> Result;
+ fn decode(stream: &mut IStream) -> Result;
}
/// Implemented for tuples with up to twelve members.
#[cfg_attr(doc, doc(fake_variadic))]
-impl Decode for (T, )
-where
- T: Decode, {
+impl Decode for (T, ) {
+ type Error = T::Error;
+
#[inline(always)]
- fn decode(stream: &mut IStream) -> Result {
+ fn decode(stream: &mut IStream) -> Result {
let value = (Decode::decode(stream)?, );
Ok(value)
}
}
impl Decode for [T; N] {
+ type Error = CollectionDecodeError>;
+
#[inline]
- fn decode(stream: &mut IStream) -> Result {
+ fn decode(stream: &mut IStream) -> Result {
// Initialise the array incrementally.
// SAFETY: Always safe.
let mut buf: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() };
- for item in &mut buf {
- let value = Decode::decode(stream)?;
+ for (i, item) in buf.iter_mut().enumerate() {
+ let value = Decode::decode(stream)
+ .map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?;
+
item.write(value);
}
- // This should be safe as `MaybeUninit` is
- // transparent to `T`, and we have initialised
+ // SAFETY: This should be safe as `MaybeUninit`
+ // is transparent to `T` and we have initialised
// every element. The original buffer is NOT
// dropped automatically, so we can just forget
// about it from this point on. `transmute` cannot
@@ -134,47 +152,60 @@ impl Decode for [T; N] {
}
}
-#[cfg(feature = "alloc")]
-#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
+#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
+#[cfg_attr(doc, doc(cfg(all(feature = "alloc", target_has_atomic = "ptr"))))]
impl Decode for Arc {
+ type Error = T::Error;
+
#[inline(always)]
- fn decode(stream: &mut IStream) -> Result {
- Ok(Self::new(Decode::decode(stream)?))
+ fn decode(stream: &mut IStream) -> Result {
+ let value = Decode::decode(stream)?;
+
+ let this = Self::new(value);
+ Ok(this)
}
}
impl Decode for bool {
+ type Error = BoolDecodeError;
+
#[inline]
- fn decode(stream: &mut IStream) -> Result {
- let value = u8::decode(stream)?;
+ fn decode(stream: &mut IStream) -> Result {
+ let value = u8::decode(stream).unwrap();
match value {
0x0 => Ok(false),
0x1 => Ok(true),
- _ => Err(DecodeError::InvalidBoolean(value))
+ _ => Err(BoolDecodeError { value })
}
}
}
impl Decode for Bound {
+ type Error = EnumDecodeError;
+
#[inline(always)]
- fn decode(stream: &mut IStream) -> Result {
- let discriminant = u8::decode(stream)?;
+ fn decode(stream: &mut IStream) -> Result {
+ let discriminant = u8::decode(stream).unwrap();
let this = match discriminant {
0x0 => {
- let bound = Decode::decode(stream)?;
+ let bound = Decode::decode(stream)
+ .map_err(EnumDecodeError::Field)?;
+
Self::Included(bound)
}
0x1 => {
- let bound = Decode::decode(stream)?;
+ let bound = Decode::decode(stream)
+ .map_err(EnumDecodeError::Field)?;
+
Self::Excluded(bound)
}
0x2 => Self::Unbounded,
- _ => return Err(DecodeError::InvalidDiscriminant(discriminant.into())),
+ value => return Err(EnumDecodeError::UnassignedDiscriminant { value }),
};
Ok(this)
@@ -184,8 +215,10 @@ impl Decode for Bound