Add more benchmarks; Redefine 'bool' scheme; Remove 'BoolDecodeError'; Rename project to *oct*; Rename 'librum' crate to 'oct'; Rename 'librum-macros' crate to 'oct-macros'; Rename 'librum-benchmarks' crate to 'oct-benchmarks'; Update lints; Update logo; Restructure tests; Rename 'IStream' to 'Input'; Rename 'OStream' to 'Output'; Make 'Output::write' and 'Input::{read, read_into}' fallible; Add 'OutputError' and 'InputError' error types; Mark 'Output::write' and 'Input::{read, read_into}' with 'const'; Add 'position', 'capacity', and 'remaining' methods to 'Output' and 'Input'; Rename 'SizeError' to 'LengthError'; Rework some error types; Fix feature flags for 'From<CStringDecodeError>' for 'GenericDecodeError'; Rename 'Buf' to 'Slot'; Remove '{Output, Input}::close'; Implement 'AsRef<[u8]>', 'Borrow<[u8]>', 'PartialEq<{Self, [u8], &[u8], &mut [u8]}>', and 'Eq' for 'Output'; Add 'as_slice' and 'as_ptr' methods to 'Output'; Add 'encode' and 'decode' modules; Update homepage link; Refactor code; Update readme;

This commit is contained in:
Gabriel Bjørnager Jensen 2024-12-20 11:40:26 +01:00
parent ef4b3c269a
commit b6f171e913
74 changed files with 1759 additions and 1445 deletions

View file

@ -1,8 +1,38 @@
# Changelog # Changelog
This is the changelog of [Librum](https://mandelbrot.dk/librum/). This is the changelog of [oct](https://mandelbrot.dk/oct/).
See `README.md` for more information. See `README.md` for more information.
## 0.14.0
* Add more benchmarks
* Redefine `bool` scheme
* Remove `BoolDecodeError`
* Rename project to *oct*
* Rename `librum` crate to `oct`
* Rename `librum-macros` crate to `oct-macros`
* Rename `librum-benchmarks` crate to `oct-benchmarks`
* Update lints
* Update logo
* Restructure tests
* Rename `IStream` to `Input`
* Rename `OStream` to `Output`
* Make `Output::write` and `Input::{read, read_into}` fallible
* Add `OutputError` and `InputError` error types
* Mark `Output::write` and `Input::{read, read_into}` with `const`
* Add `position`, `capacity`, and `remaining` methods to `Output` and `Input`
* Rename `SizeError` to `LengthError`
* Rework some error types
* Fix feature flags for `From<CStringDecodeError>` for `GenericDecodeError`
* Rename `Buf` to `Slot`
* Remove `{Output, Input}::close`
* Implement `AsRef<[u8]>`, `Borrow<[u8]>`, `PartialEq<{Self, [u8], &[u8], &mut [u8]}>`, and `Eq` for `Output`
* Add `as_slice` and `as_ptr` methods to `Output`
* Add `encode` and `decode` modules
* Update homepage link
* Refactor code
* Update readme
## 0.13.1 ## 0.13.1
* Update readme * Update readme

View file

@ -1,13 +1,13 @@
[workspace] [workspace]
members = ["librum", "librum-benchmarks", "librum-macros"] members = ["oct", "oct-benchmarks", "oct-macros"]
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
authors = ["Gabriel Bjørnager Jensen"] authors = ["Gabriel Bjørnager Jensen"]
description = "Binary (de)serialiser." description = "Binary (de)serialiser."
readme = "README.md" readme = "README.md"
homepage = "https://achernar.dk/index.php?p=bzipper" homepage = "https://docs.rs/oct/latest/oct/"
repository = "https://mandelbrot.dk/librum/" repository = "https://mandelbrot.dk/oct/"
license = "LGPL-3.0-or-later" license = "LGPL-3.0-or-later"
keywords = ["api", "encoding", "io", "network", "no-std"] keywords = ["api", "encoding", "io", "network", "no-std"]
categories = ["encoding", "network-programming", "parsing"] categories = ["encoding", "network-programming", "parsing"]
@ -35,6 +35,7 @@ empty_enum_variants_with_brackets = "warn"
empty_line_after_doc_comments = "warn" empty_line_after_doc_comments = "warn"
empty_line_after_outer_attr = "warn" empty_line_after_outer_attr = "warn"
empty_structs_with_brackets = "warn" empty_structs_with_brackets = "warn"
enum_glob_use = "forbid"
enum_variant_names = "allow" enum_variant_names = "allow"
equatable_if_let = "warn" equatable_if_let = "warn"
excessive_precision = "allow" excessive_precision = "allow"
@ -52,7 +53,6 @@ from_iter_instead_of_collect = "warn"
future_not_send = "deny" future_not_send = "deny"
if_not_else = "warn" if_not_else = "warn"
if_then_some_else_none = "warn" if_then_some_else_none = "warn"
ignored_unit_patterns = "warn"
impl_trait_in_params = "warn" impl_trait_in_params = "warn"
implicit_clone = "warn" implicit_clone = "warn"
imprecise_flops = "deny" imprecise_flops = "deny"

View file

@ -1,8 +1,6 @@
# Librum oct 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 directly translating into binary encodings (whilst the mentioned crates specifically use Serde as a middle layer).
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. The original goal of this project was specifically to guarantee size constraints for encodings on a per-type basis at compile-time.
Therefore, this crate may be more suited for networking or other cases where many allocations are unwanted. Therefore, this crate may be more suited for networking or other cases where many allocations are unwanted.
@ -13,24 +11,25 @@ This crate is compatible with `no_std`.
## Performance ## Performance
As Librum is optimised exclusively for a single, binary format, it *may* outperform other libraries that are more generic in nature. As oct is optimised exclusively for a single, binary format, it *may* outperform other libraries that are more generic in nature.
The `librum-benchmarks` binary compares multiple scenarios using Librum and other, similar crates. The `oct-benchmarks` binary compares multiple scenarios using oct and other, similar crates.
According to my runs on an AMD Ryzen 7 3700X with default settings, these benchmarks indicate that Librum usually outperforms the other tested crates &ndash; as demonstrated in the following table: According to my runs on an AMD Ryzen 7 3700X with default settings, these benchmarks indicate that oct usually outperforms the other tested crates -- as demonstrated in the following table:
| Benchmark | [Bincode] | [Borsh] | Librum | [Postcard] | | Benchmark | [Bincode] | [Borsh] | oct | [Postcard] |
| :--------------------------------- | --------: | ------: | ------: | ---------: | | :--------------------------------- | --------: | ------: | ------: | ---------: |
| `encode_u8` | 1.004 | 0.947 | 0.806 | 0.972 | | `encode_u8` | 0.968 | 0.857 | 0.733 | 0.979 |
| `encode_u32` | 1.130 | 1.084 | 0.749 | 2.793 | | `encode_u32` | 1.065 | 0.999 | 0.730 | 2.727 |
| `encode_u128` | 2.340 | 2.328 | 1.543 | 6.380 | | `encode_u128` | 2.168 | 2.173 | 1.510 | 6.246 |
| `encode_struct_unit` | 0.000 | 0.000 | 0.000 | 0.000 | | `encode_struct_unit` | 0.000 | 0.000 | 0.000 | 0.000 |
| `encode_struct_unnamed` | 1.218 | 1.160 | 0.838 | 2.392 | | `encode_struct_unnamed` | 1.241 | 1.173 | 0.823 | 3.350 |
| `encode_struct_named` | 3.077 | 1.501 | 0.975 | 3.079 | | `encode_struct_named` | 3.079 | 1.507 | 0.973 | 3.082 |
| `encode_enum_unit` | 0.260 | 0.310 | 0.000 | 0.303 | | `encode_enum_unit` | 0.246 | 0.297 | 0.000 | 0.295 |
| `decode_u8` | 1.116 | 1.106 | 1.110 | 1.102 | | `decode_u8` | 0.942 | 0.962 | 0.922 | 0.923 |
| `decode_non_zero_u8` | 1.228 | 1.236 | 1.269 | 1.263 | | `decode_non_zero_u8` | 1.126 | 1.159 | 1.127 | 1.160 |
| **Total time** &#8594; | 11.373 | 9.672 | 7.291 | 18.284 | | `decode_bool` | 1.040 | 1.099 | 1.055 | 1.177 |
| **Total deviation (p.c.)** &#8594; | +56 | +33 | ±0 | +150 | | **Total time** &#8594; | 11.873 | 10.225 | 7.873 | 18.939 |
| **Total deviation (p.c.)** &#8594; | +51 | +30 | ±0 | +141 |
[Bincode]: https://crates.io/crates/bincode/ [Bincode]: https://crates.io/crates/bincode/
[Borsh]: https://crates.io/crates/borsh/ [Borsh]: https://crates.io/crates/borsh/
@ -38,9 +37,9 @@ According to my runs on an AMD Ryzen 7 3700X with default settings, these benchm
All quantities are measured in seconds unless otherwise noted. All quantities are measured in seconds unless otherwise noted.
Currently, Librum's weakest point seems to be decoding. Currently, oct's weakest point seems to be decoding.
Please note that I myself find large (relatively speaking) inconsistencies between runs in these last two benchmarks. Please note that I myself find large (relatively speaking) inconsistencies between runs in these last two benchmarks.
Do feel free to conduct your own tests of Librum. Do feel free to conduct your own tests of oct.
## Data model ## Data model
@ -59,14 +58,16 @@ It may therefore be undesired to store encodings long-term.
This crate revolves around the `Encode` and `Decode` traits, both of which handle conversions to and from byte streams. This crate revolves around the `Encode` and `Decode` traits, both of which handle conversions to and from byte streams.
Many standard types come implemented with Librum, including most primitives as well as some standard library types such as `Option` and `Result`. Many standard types come implemented with oct, 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. Some [features](#feature-flags) enable an extended set of implementations.
It is recommended in most cases to simply derive these two traits for user-defined 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 user-defined types (although this is only supported with enumerations and structures -- not untagged unions).
Here, each field is *chained* according to declaration order: Here, each field is *chained* according to declaration order:
```rust ```rust
use librum::{Buf, Decode, Encode}; use oct::Slot;
use oct::decode::Decode;
use oct::encode::Encode;
#[derive(Debug, Decode, Encode, PartialEq)] #[derive(Debug, Decode, Encode, PartialEq)]
struct Ints { struct Ints {
@ -85,7 +86,7 @@ const VALUE: Ints = Ints {
value4: 0x1E_1D_1C_1B_1A_19_18_17_16_15_14_13_12_11_10_0F, value4: 0x1E_1D_1C_1B_1A_19_18_17_16_15_14_13_12_11_10_0F,
}; };
let mut buf = Buf::with_capacity(0x100); let mut buf = Slot::with_capacity(0x100);
buf.write(VALUE).unwrap(); buf.write(VALUE).unwrap();
@ -108,18 +109,18 @@ assert_eq!(buf.read().unwrap(), VALUE);
The `Encode` and `Decode` traits both rely on streams for carrying the manipulated bytes. 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). These streams are separated into two type: *output streams* and *input streams*.
The `Buf` type can be used to handle these streams. The `Slot` type can be used to handle these streams.
### Encoding ### 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 `Output` object:
```rust ```rust
use librum::{Encode, OStream, SizedEncode}; use oct::encode::{Encode, Output, SizedEncode};
let mut buf = [0x00; char::MAX_ENCODED_SIZE]; let mut buf = [0x00; char::MAX_ENCODED_SIZE];
let mut stream = OStream::new(&mut buf); let mut stream = Output::new(&mut buf);
'Ж'.encode(&mut stream).unwrap(); 'Ж'.encode(&mut stream).unwrap();
@ -129,10 +130,10 @@ assert_eq!(buf, [0x16, 0x04, 0x00, 0x00].as_slice());
Streams can also be used to chain multiple objects together: Streams can also be used to chain multiple objects together:
```rust ```rust
use librum::{Encode, OStream, SizedEncode}; use oct::encode::{Encode, Output, SizedEncode};
let mut buf = [0x0; char::MAX_ENCODED_SIZE * 0x5]; let mut buf = [0x0; char::MAX_ENCODED_SIZE * 0x5];
let mut stream = OStream::new(&mut buf); let mut stream = Output::new(&mut buf);
// Note: For serialising multiple characters, the // Note: For serialising multiple characters, the
// `String` and `SizedStr` types are usually // `String` and `SizedStr` types are usually
@ -156,26 +157,26 @@ If the encoded type additionally implements `SizedEncode`, then the maximum size
### Decoding ### Decoding
Decoding works with a similar syntax to encoding. 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` method with an `Input` object:
```rust ```rust
use librum::{Decode, IStream}; use oct::decode::{Decode, Input};
let data = [0x54, 0x45]; let data = [0x54, 0x45];
let mut stream = IStream::new(&data); let mut stream = Input::new(&data);
assert_eq!(u16::decode(&mut stream).unwrap(), 0x4554); assert_eq!(u16::decode(&mut stream).unwrap(), 0x4554);
// Data can theoretically be reinterpretred: // Data can theoretically be reinterpretred:
stream = IStream::new(&data); stream = Input::new(&data);
assert_eq!(u8::decode(&mut stream).unwrap(), 0x54); assert_eq!(u8::decode(&mut stream).unwrap(), 0x54);
assert_eq!(u8::decode(&mut stream).unwrap(), 0x45); assert_eq!(u8::decode(&mut stream).unwrap(), 0x45);
// Including as tuples: // Including as tuples:
stream = IStream::new(&data); stream = Input::new(&data);
assert_eq!(<(u8, u8)>::decode(&mut stream).unwrap(), (0x54, 0x45)); assert_eq!(<(u8, u8)>::decode(&mut stream).unwrap(), (0x54, 0x45));
``` ```
@ -185,7 +186,9 @@ assert_eq!(<(u8, u8)>::decode(&mut stream).unwrap(), (0x54, 0x45));
A UDP server/client for geographic data: A UDP server/client for geographic data:
```rust ```rust
use librum::{Buf, Encode, Decode, SizedEncode}; use oct::Slot;
use oct::decode::Decode;
use oct::encode::{Encode, SizedEncode};
use std::io; use std::io;
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket}; use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
use std::thread::spawn; use std::thread::spawn;
@ -221,8 +224,8 @@ enum Response {
struct Party { struct Party {
pub socket: UdpSocket, pub socket: UdpSocket,
pub request_buf: Buf::<Request>, pub request_buf: Slot::<Request>,
pub response_buf: Buf::<Response>, pub response_buf: Slot::<Response>,
} }
impl Party { impl Party {
@ -232,8 +235,8 @@ impl Party {
let this = Self { let this = Self {
socket, socket,
request_buf: Buf::new(), request_buf: Slot::new(),
response_buf: Buf::new(), response_buf: Slot::new(),
}; };
Ok(this) Ok(this)
@ -286,28 +289,28 @@ spawn(move || {
## Feature flags ## Feature flags
Librum defines the following features: oct defines the following features:
* *`alloc`: Enables the `Buf` type and implementations for e.g. `Box` and `Arc` * *`alloc`: Enables the `Slot` type and implementations for e.g. `Box` and `Arc`
* *`proc-macro`: Pulls the procedural macros from the `librum-macros` crate * *`proc-macro`: Pulls the procedural macros from the [`oct-macros`](https://crates.io/crates/oct-macros/) crate
* *`std`: Enables implementations for types such as `Mutex` and `RwLock` * *`std`: Enables implementations for types such as `Mutex` and `RwLock`
Features marked with * are enabled by default. Features marked with * are enabled by default.
## Documentation ## Documentation
Librum has its documentation written in-source for use by `rustdoc`. oct 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. See [Docs.rs](https://docs.rs/oct/latest/oct/) for an on-line, rendered instance.
Currently, these docs make use of some unstable features for the sake of readability. Currently, these docs make use of some unstable features for the sake of readability.
The nightly toolchain is therefore required when rendering them. The nightly toolchain is therefore required when rendering them.
## Contribution ## Contribution
Librum does not accept source code contributions at the moment. oct does not accept source code contributions at the moment.
This is a personal choice by the maintainer and may be undone in the future. 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/librum/issues/) or (preferably) [GitHub](https://github.com/bjoernager/librum/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/oct/issues/) or (preferably) [GitHub](https://github.com/bjoernager/oct/issues/) if you feel the need to express any concerns over the project.
## Copyright & Licence ## Copyright & Licence

View file

@ -1,7 +1,17 @@
<svg height="72" width="72" xmlns="http://www.w3.org/2000/svg"> <svg height="96" width="96" xmlns="http://www.w3.org/2000/svg">
<mask id="z"> <mask id="tHorizontalArm">
<polygon fill="white" points="12,12 72,12 60,24 48,24 42,30 66,30 54,42 48,42 42,48 72,48 60,60 0,60 12,48 24,48 30,42 5,42 18,30 24,30 30,24 0,24" /> <rect fill="white" height="100%" width="100%" x="0" y="0" />
<circle cx="48" cy="48" fill="none" r="32" stroke="black" stroke-width="20" />
</mask> </mask>
<rect fill="#FFFFFF" height="100%" mask="url(#z)" width="100%" x="0" y="0" /> <mask id="glyph">
<!-- O: -->
<circle cx="48" cy="48" fill="none" r="32" stroke="white" stroke-width="16" />
<!-- T: -->
<rect fill="white" height="16" paint-order="stroke" stroke="black" stroke-width="4" width="96" x="0" y="40" />
<rect fill="white" height="96" mask="url(#tHorizontalArm)" width="16" x="40" y="0" />
</mask>
<rect fill="#FFFFFF" height="100%" mask="url(#glyph)" width="100%" x="0" y="0" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 328 B

After

Width:  |  Height:  |  Size: 676 B

Before After
Before After

View file

@ -1,8 +0,0 @@
<svg height="96" width="96" xmlns="http://www.w3.org/2000/svg">
<mask id="z">
<polygon fill="white" points="24,24 84,24 72,36 60,36 54,42 78,42 66,54 60,54 54,60 84,60 72,72 12,72 24,60 36,60 42,54 17,54 30,42 36,42 42,36 12,36" />
</mask>
<rect fill="#02764a" height="100%" width="100%" x="0" y="0" /> <!-- oklch(50% 0.115300 158.520) -->
<rect fill="#FFFFFF" height="100%" mask="url(#z)" width="100%" x="0" y="0" />
</svg>

Before

Width:  |  Height:  |  Size: 432 B

View file

@ -1,43 +0,0 @@
// 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 <https://www.gnu.org/licenses/>.
use core::error::Error;
use core::fmt::{self, Display, Formatter};
/// A boolean could not be decoded.
///
/// The encoding scheme for [`bool`] only defines the 8-bit values `0` and `1` (as `false` and `true`, respectively).
/// If any other 8-bit is read by <code>&lt;bool as [Decode](crate::Decode)&gt;::[decode](crate::Decode::decode)</code>, then an instance of this type is returned.
#[derive(Debug)]
#[must_use]
pub struct BoolDecodeError {
/// The invalid value.
pub value: u8,
}
impl Display for BoolDecodeError {
#[inline(always)]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "expected boolean but got `{:#02X}`", self.value)
}
}
impl Error for BoolDecodeError { }

View file

@ -1,74 +0,0 @@
// 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 <https://www.gnu.org/licenses/>.
use core::ptr::copy_nonoverlapping;
/// Byte stream suitable for output.
pub struct OStream<'a> {
buf: &'a mut [u8],
pos: usize,
}
impl<'a> OStream<'a> {
/// Constructs a new o-stream.
#[inline(always)]
#[must_use]
pub const fn new(buf: &'a mut [u8]) -> Self {
Self { buf, pos: 0x0 }
}
/// Writes bytes to the stream.
///
/// # Panics
///
/// If the requested amount of bytes could not exactly be written, then this method will panic.
#[inline]
pub fn write(&mut self, data: &[u8]) {
let remaining = self.buf.len() - self.pos;
let count = data.len();
assert!(
remaining >= count,
"cannot write ({count}) bytes at ({}) to stream with capacity of ({})",
self.pos,
self.buf.len(),
);
unsafe {
let src = data.as_ptr();
let dst = self.buf.as_mut_ptr().add(self.pos);
copy_nonoverlapping(src, dst, count);
}
self.pos += count;
}
/// Closes the stream.
///
/// The total ammount of bytes written is returned.
#[inline(always)]
pub const fn close(self) -> usize {
let Self { pos, .. } = self;
pos
}
}

View file

@ -1,8 +1,8 @@
[package] [package]
name = "librum-benchmarks" name = "oct-benchmarks"
version = "0.13.1" version = "0.14.0"
edition = "2021" edition = "2021"
description = "Librum benchmarks." description = "oct benchmarks."
authors.workspace = true authors.workspace = true
readme.workspace = true readme.workspace = true
@ -10,7 +10,7 @@ homepage.workspace = true
repository.workspace = true repository.workspace = true
[dependencies] [dependencies]
librum = { path = "../librum", version = "0.13.0", features = ["proc-macro"]} oct = { path = "../oct", version = "0.14.0", features = ["proc-macro"]}
bincode = "1.3.0" bincode = "1.3.0"
rand = "0.8.0" rand = "0.8.0"

View file

@ -18,7 +18,7 @@ macro_rules! benchmark {
borsh: $borsh_op:block$(,)? borsh: $borsh_op:block$(,)?
librum: $librum_op:block$(,)? oct: $oct_op:block$(,)?
postcard: $postcard_op:block$(,)? postcard: $postcard_op:block$(,)?
}$(,)?)+ }$(,)?)+
@ -54,7 +54,7 @@ macro_rules! benchmark {
let mut total_bincode_duration = 0.0; let mut total_bincode_duration = 0.0;
let mut total_borsh_duration = 0.0; let mut total_borsh_duration = 0.0;
let mut total_librum_duration = 0.0; let mut total_oct_duration = 0.0;
let mut total_postcard_duration = 0.0; let mut total_postcard_duration = 0.0;
$({ $({
@ -63,7 +63,7 @@ macro_rules! benchmark {
let mut bincode_duration = 0.0; let mut bincode_duration = 0.0;
let mut borsh_duration = 0.0; let mut borsh_duration = 0.0;
let mut librum_duration = 0.0; let mut oct_duration = 0.0;
let mut postcard_duration = 0.0; let mut postcard_duration = 0.0;
for i in 0x0..TEST_COUNT { for i in 0x0..TEST_COUNT {
@ -73,7 +73,7 @@ macro_rules! benchmark {
bincode_duration += time! { $bincode_op }; bincode_duration += time! { $bincode_op };
borsh_duration += time! { $borsh_op }; borsh_duration += time! { $borsh_op };
librum_duration += time! { $librum_op }; oct_duration += time! { $oct_op };
postcard_duration += time! { $postcard_op }; postcard_duration += time! { $postcard_op };
eprint!("\u{001B}[000m"); eprint!("\u{001B}[000m");
@ -83,37 +83,37 @@ macro_rules! benchmark {
bincode_duration /= f64::from(TEST_COUNT); bincode_duration /= f64::from(TEST_COUNT);
borsh_duration /= f64::from(TEST_COUNT); borsh_duration /= f64::from(TEST_COUNT);
librum_duration /= f64::from(TEST_COUNT); oct_duration /= f64::from(TEST_COUNT);
postcard_duration /= f64::from(TEST_COUNT); postcard_duration /= f64::from(TEST_COUNT);
eprint!("\u{001B}[000m"); eprint!("\u{001B}[000m");
eprintln!("bincode: {}", format_score(bincode_duration, librum_duration)); eprintln!("bincode: {}", format_score(bincode_duration, oct_duration));
eprintln!("borsh: {}", format_score(borsh_duration, librum_duration)); eprintln!("borsh: {}", format_score(borsh_duration, oct_duration));
eprintln!("librum: {}", format_score(librum_duration, librum_duration)); eprintln!("oct: {}", format_score(oct_duration, oct_duration));
eprintln!("postcard: {}", format_score(postcard_duration, librum_duration)); eprintln!("postcard: {}", format_score(postcard_duration, oct_duration));
total_bincode_duration += bincode_duration; total_bincode_duration += bincode_duration;
total_borsh_duration += borsh_duration; total_borsh_duration += borsh_duration;
total_librum_duration += librum_duration; total_oct_duration += oct_duration;
total_postcard_duration += postcard_duration; total_postcard_duration += postcard_duration;
})* })*
eprintln!(); eprintln!();
eprintln!("\u{001B}[001mtotal score:\u{001B}[022m"); eprintln!("\u{001B}[001mtotal score:\u{001B}[022m");
eprintln!("bincode: {}", format_score(total_bincode_duration, total_librum_duration)); eprintln!("bincode: {}", format_score(total_bincode_duration, total_oct_duration));
eprintln!("borsh: {}", format_score(total_borsh_duration, total_librum_duration)); eprintln!("borsh: {}", format_score(total_borsh_duration, total_oct_duration));
eprintln!("librum: {}", format_score(total_librum_duration, total_librum_duration)); eprintln!("oct: {}", format_score(total_oct_duration, total_oct_duration));
eprintln!("postcard: {}", format_score(total_postcard_duration, total_librum_duration)); eprintln!("postcard: {}", format_score(total_postcard_duration, total_oct_duration));
}}; }};
} }
#[derive(librum::Decode, librum::Encode, librum::SizedEncode)] #[derive(oct::decode::Decode, oct::encode::Encode, oct::encode::SizedEncode)]
#[derive(borsh::BorshSerialize)] #[derive(borsh::BorshSerialize)]
#[derive(serde::Deserialize, serde::Serialize)] #[derive(serde::Deserialize, serde::Serialize)]
#[repr(transparent)] #[repr(transparent)]
struct Unit; struct Unit;
#[derive(librum::Decode, librum::Encode, librum::SizedEncode)] #[derive(oct::decode::Decode, oct::encode::Encode, oct::encode::SizedEncode)]
#[derive(borsh::BorshSerialize)] #[derive(borsh::BorshSerialize)]
#[derive(serde::Deserialize, serde::Serialize)] #[derive(serde::Deserialize, serde::Serialize)]
#[repr(transparent)] #[repr(transparent)]
@ -127,21 +127,12 @@ impl Unnamed {
} }
} }
#[derive(librum::Decode, librum::Encode, librum::SizedEncode)] #[derive(oct::decode::Decode, oct::encode::Encode, oct::encode::SizedEncode)]
#[derive(borsh::BorshSerialize)] #[derive(borsh::BorshSerialize)]
#[derive(serde::Deserialize, serde::Serialize)] #[derive(serde::Deserialize, serde::Serialize)]
#[repr(transparent)] #[repr(transparent)]
struct Named { buf: [u8; 0x8] } struct Named { buf: [u8; 0x8] }
#[derive(librum::Decode, librum::Encode, librum::SizedEncode)]
#[derive(borsh::BorshSerialize)]
#[derive(serde::Deserialize, serde::Serialize)]
enum Enum {
Unit(Unit),
Unnamed(Unnamed),
Named(Named),
}
impl Named { impl Named {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
@ -161,6 +152,15 @@ impl Named {
} }
} }
#[derive(oct::decode::Decode, oct::encode::Encode, oct::encode::SizedEncode)]
#[derive(borsh::BorshSerialize)]
#[derive(serde::Deserialize, serde::Serialize)]
enum Enum {
Unit(Unit),
Unnamed(Unnamed),
Named(Named),
}
fn generate_random_data<T>(item_size: usize, value_count: usize) -> impl Iterator<Item = u8> fn generate_random_data<T>(item_size: usize, value_count: usize) -> impl Iterator<Item = u8>
where where
T: Immutable + IntoBytes + Sized, T: Immutable + IntoBytes + Sized,
@ -180,15 +180,15 @@ where
} }
fn main() { fn main() {
println!("#####################"); println!("##################");
println!("# LIBRUM BENCHMARKS #"); println!("# OCT BENCHMARKS #");
println!("#####################"); println!("##################");
println!(); println!();
println!("Each benchmark has a version written for the following crates:"); println!("Each benchmark has a version written for the following crates:");
println!(); println!();
println!("- Bincode: <https://crates.io/crates/bincode/>"); println!("- Bincode: <https://crates.io/crates/bincode/>");
println!("- Borsh: <https://crates.io/crates/borsh/>"); println!("- Borsh: <https://crates.io/crates/borsh/>");
println!("- Librum: <https://crates.io/crates/librum/>"); println!("- oct: <https://crates.io/crates/oct/>");
println!("- Postcard: <https://crates.io/crates/postcard/>"); println!("- Postcard: <https://crates.io/crates/postcard/>");
println!(); println!();
println!("The total time the benchmark took (including memory allocations and dealloca-"); println!("The total time the benchmark took (including memory allocations and dealloca-");
@ -198,10 +198,10 @@ fn main() {
println!(); println!();
println!("When every benchmark has concluded, the total run time and vps is listed for"); 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!("each crate. A percantage additionally compares the run time between the listed");
println!("crate and librum (which should always be c. `0%` for Librum itself). DO NOTE"); println!("crate and oct (which should always be c. `0%` for oct itself). DO NOTE THAT");
println!("THAT THESE FINAL RESULTS INDICATE A NON-WEIGHTED AVERAGE ACROSS BENCHMARKS. It"); println!("THESE FINAL RESULTS INDICATE A NON-WEIGHTED AVERAGE ACROSS BENCHMARKS. It can");
println!("can therefore be skewed relative to real-world performance by the similarity of"); println!("therefore be skewed relative to real-world performance by the similarity of some");
println!("some benchmarks."); println!("benchmarks.");
println!(); println!();
eprintln!("test_count: {TEST_COUNT}"); eprintln!("test_count: {TEST_COUNT}");
@ -233,13 +233,13 @@ fn main() {
} }
} }
librum: { oct: {
use librum::{Encode, OStream, SizedEncode}; use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = u8::MAX_ENCODED_SIZE; const ITEM_SIZE: usize = u8::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice(); let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf); let mut stream = Output::new(&mut buf);
for _ in 0x0..VALUE_COUNT { for _ in 0x0..VALUE_COUNT {
random::<u8>().encode(&mut stream).unwrap(); random::<u8>().encode(&mut stream).unwrap();
@ -280,13 +280,13 @@ fn main() {
} }
} }
librum: { oct: {
use librum::{Encode, OStream, SizedEncode}; use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = u32::MAX_ENCODED_SIZE; const ITEM_SIZE: usize = u32::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice(); let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf); let mut stream = Output::new(&mut buf);
for _ in 0x0..VALUE_COUNT { for _ in 0x0..VALUE_COUNT {
random::<u32>().encode(&mut stream).unwrap(); random::<u32>().encode(&mut stream).unwrap();
@ -327,13 +327,13 @@ fn main() {
} }
} }
librum: { oct: {
use librum::{Encode, OStream, SizedEncode}; use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = u128::MAX_ENCODED_SIZE; const ITEM_SIZE: usize = u128::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice(); let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf); let mut stream = Output::new(&mut buf);
for _ in 0x0..VALUE_COUNT { for _ in 0x0..VALUE_COUNT {
random::<u128>().encode(&mut stream).unwrap(); random::<u128>().encode(&mut stream).unwrap();
@ -374,13 +374,13 @@ fn main() {
} }
} }
librum: { oct: {
use librum::{Encode, OStream, SizedEncode}; use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = Unit::MAX_ENCODED_SIZE; const ITEM_SIZE: usize = Unit::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice(); let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf); let mut stream = Output::new(&mut buf);
for _ in 0x0..VALUE_COUNT { for _ in 0x0..VALUE_COUNT {
Unit.encode(&mut stream).unwrap(); Unit.encode(&mut stream).unwrap();
@ -421,13 +421,13 @@ fn main() {
} }
} }
librum: { oct: {
use librum::{Encode, OStream, SizedEncode}; use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = Unnamed::MAX_ENCODED_SIZE; const ITEM_SIZE: usize = Unnamed::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice(); let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf); let mut stream = Output::new(&mut buf);
for _ in 0x0..VALUE_COUNT { for _ in 0x0..VALUE_COUNT {
Unnamed::from_char(random()).encode(&mut stream).unwrap(); Unnamed::from_char(random()).encode(&mut stream).unwrap();
@ -468,13 +468,13 @@ fn main() {
} }
} }
librum: { oct: {
use librum::{Encode, OStream, SizedEncode}; use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = Named::MAX_ENCODED_SIZE; const ITEM_SIZE: usize = Named::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice(); let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf); let mut stream = Output::new(&mut buf);
for _ in 0x0..VALUE_COUNT { for _ in 0x0..VALUE_COUNT {
Named::from_u64(random()).encode(&mut stream).unwrap(); Named::from_u64(random()).encode(&mut stream).unwrap();
@ -519,15 +519,15 @@ fn main() {
} }
} }
librum: { oct: {
use librum::{Encode, OStream, SizedEncode}; use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = const ITEM_SIZE: usize =
isize::MAX_ENCODED_SIZE // discriminant isize::MAX_ENCODED_SIZE // discriminant
+ Unit::MAX_ENCODED_SIZE; + Unit::MAX_ENCODED_SIZE;
let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice(); let mut buf = vec![0x00; ITEM_SIZE * VALUE_COUNT].into_boxed_slice();
let mut stream = OStream::new(&mut buf); let mut stream = Output::new(&mut buf);
for _ in 0x0..VALUE_COUNT { for _ in 0x0..VALUE_COUNT {
Enum::Unit(Unit).encode(&mut stream).unwrap(); Enum::Unit(Unit).encode(&mut stream).unwrap();
@ -572,13 +572,14 @@ fn main() {
} }
} }
librum: { oct: {
use librum::{Decode, IStream, SizedEncode}; use oct::decode::{Decode, Input};
use oct::encode::SizedEncode;
const ITEM_SIZE: usize = u8::MAX_ENCODED_SIZE; const ITEM_SIZE: usize = u8::MAX_ENCODED_SIZE;
let buf: Box<[_]> = generate_random_data::<u8>(ITEM_SIZE, VALUE_COUNT).collect(); let buf: Box<[_]> = generate_random_data::<u8>(ITEM_SIZE, VALUE_COUNT).collect();
let mut stream = IStream::new(&buf); let mut stream = Input::new(&buf);
for _ in 0x0..VALUE_COUNT { for _ in 0x0..VALUE_COUNT {
let _ = u8::decode(&mut stream).unwrap(); let _ = u8::decode(&mut stream).unwrap();
@ -623,13 +624,14 @@ fn main() {
} }
} }
librum: { oct: {
use librum::{Decode, IStream, SizedEncode}; use oct::decode::{Decode, Input};
use oct::encode::SizedEncode;
const ITEM_SIZE: usize = NonZero::<u8>::MAX_ENCODED_SIZE; const ITEM_SIZE: usize = NonZero::<u8>::MAX_ENCODED_SIZE;
let buf: Box<[_]> = generate_random_data::<NonZero<u8>>(ITEM_SIZE, VALUE_COUNT).collect(); let buf: Box<[_]> = generate_random_data::<NonZero<u8>>(ITEM_SIZE, VALUE_COUNT).collect();
let mut stream = IStream::new(&buf); let mut stream = Input::new(&buf);
for _ in 0x0..VALUE_COUNT { for _ in 0x0..VALUE_COUNT {
let _ = NonZero::<u8>::decode(&mut stream).unwrap(); let _ = NonZero::<u8>::decode(&mut stream).unwrap();
@ -648,5 +650,57 @@ fn main() {
} }
} }
} }
decode_bool: {
bincode: {
const ITEM_SIZE: usize = size_of::<bool>();
let buf: Box<[_]> = generate_random_data::<bool>(ITEM_SIZE, VALUE_COUNT).collect();
for i in 0x0..VALUE_COUNT {
let data = array::from_ref(&buf[i]).as_slice();
let _: bool = bincode::deserialize_from(data).unwrap();
}
}
borsh: {
const ITEM_SIZE: usize = size_of::<bool>();
let buf: Box<[_]> = generate_random_data::<bool>(ITEM_SIZE, VALUE_COUNT).collect();
for i in 0x0..VALUE_COUNT {
let data = array::from_ref(&buf[i]).as_slice();
let _: bool = borsh::from_slice(data).unwrap();
}
}
oct: {
use oct::decode::{Decode, Input};
use oct::encode::SizedEncode;
const ITEM_SIZE: usize = bool::MAX_ENCODED_SIZE;
let buf: Box<[_]> = generate_random_data::<bool>(ITEM_SIZE, VALUE_COUNT).collect();
let mut stream = Input::new(&buf);
for _ in 0x0..VALUE_COUNT {
let _ = bool::decode(&mut stream).unwrap();
}
}
postcard: {
const ITEM_SIZE: usize = size_of::<bool>();
let buf: Box<[_]> = generate_random_data::<bool>(ITEM_SIZE, VALUE_COUNT).collect();
for i in 0x0..VALUE_COUNT {
let data = array::from_ref(&buf[i]).as_slice();
let _: bool = postcard::from_bytes(data).unwrap();
}
}
}
}; };
} }

View file

@ -1,8 +1,8 @@
[package] [package]
name = "librum-macros" name = "oct-macros"
version = "0.13.1" version = "0.14.0"
edition = "2021" edition = "2021"
documentation = "https://docs.rs/librum-macros/" documentation = "https://docs.rs/oct-macros/"
authors.workspace = true authors.workspace = true
description.workspace = true description.workspace = true

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use std::borrow::Borrow; use std::borrow::Borrow;

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
@ -82,14 +82,12 @@ impl Debug for GenericName {
impl ToTokens for GenericName { impl ToTokens for GenericName {
#[inline(always)] #[inline(always)]
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
use GenericName::*;
match *self { match *self {
| Const(ref ident) | Self::Const(ref ident)
| Ty( ref ident) | Self::Ty( ref ident)
=> ident.to_tokens(tokens), => ident.to_tokens(tokens),
Lifetime(ref lifetime) => lifetime.to_tokens(tokens), Self::Lifetime(ref lifetime) => lifetime.to_tokens(tokens),
} }
} }
} }

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::{GenericName, Repr}; use crate::{GenericName, Repr};

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::{Discriminants, Repr}; use crate::{Discriminants, Repr};
@ -38,9 +38,9 @@ pub fn decode_enum(data: DataEnum, repr: Repr) -> TokenStream {
let commands = iter::repeat_n( let commands = iter::repeat_n(
quote! { quote! {
::librum::Decode::decode(stream) ::oct::decode::Decode::decode(stream)
.map_err(::core::convert::Into::<::librum::error::GenericDecodeError>::into) .map_err(::core::convert::Into::<::oct::error::GenericDecodeError>::into)
.map_err(::librum::error::EnumDecodeError::Field)? .map_err(::oct::error::EnumDecodeError::BadField)?
}, },
variant.fields.len(), variant.fields.len(),
); );
@ -62,18 +62,18 @@ pub fn decode_enum(data: DataEnum, repr: Repr) -> TokenStream {
}); });
quote! { quote! {
type Error = ::librum::error::EnumDecodeError<#repr, ::librum::error::GenericDecodeError>; type Error = ::oct::error::EnumDecodeError<#repr, ::oct::error::GenericDecodeError>;
#[inline] #[inline]
fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result<Self, Self::Error> { fn decode(stream: &mut ::oct::decode::Input) -> ::core::result::Result<Self, Self::Error> {
let discriminant = <#repr as ::librum::Decode>::decode(stream) let discriminant = <#repr as ::oct::decode::Decode>::decode(stream)
.map_err(::core::convert::Into::<::core::convert::Infallible>::into) .map_err(::core::convert::Into::<::core::convert::Infallible>::into)
.map_err(::librum::error::EnumDecodeError::InvalidDiscriminant)?; .map_err(::oct::error::EnumDecodeError::InvalidDiscriminant)?;
let this = match discriminant { let this = match discriminant {
#(#discriminants => #values,)* #(#discriminants => #values,)*
value => return ::core::result::Result::Err(::librum::error::EnumDecodeError::UnassignedDiscriminant { value }), value => return ::core::result::Result::Err(::oct::error::EnumDecodeError::UnassignedDiscriminant { value }),
}; };
::core::result::Result::Ok(this) ::core::result::Result::Ok(this)

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
@ -28,8 +28,8 @@ use std::iter;
pub fn decode_struct(data: DataStruct) -> TokenStream { pub fn decode_struct(data: DataStruct) -> TokenStream {
let commands = iter::repeat_n( let commands = iter::repeat_n(
quote! { quote! {
::librum::Decode::decode(stream) ::oct::decode::Decode::decode(stream)
.map_err(::core::convert::Into::<::librum::error::GenericDecodeError>::into)? .map_err(::core::convert::Into::<::oct::error::GenericDecodeError>::into)?
}, },
data.fields.len(), data.fields.len(),
); );
@ -50,10 +50,10 @@ pub fn decode_struct(data: DataStruct) -> TokenStream {
}; };
quote! { quote! {
type Error = ::librum::error::GenericDecodeError; type Error = ::oct::error::GenericDecodeError;
#[inline] #[inline]
fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result<Self, Self::Error> { fn decode(stream: &mut ::oct::decode::Input) -> ::core::result::Result<Self, Self::Error> {
let this = #value; let this = #value;
::core::result::Result::Ok(this) ::core::result::Result::Ok(this)
} }

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::{Discriminants, Repr}; use crate::{Discriminants, Repr};
@ -66,21 +66,21 @@ pub fn encode_enum(data: DataEnum, repr: Repr) -> TokenStream {
}); });
quote! { quote! {
type Error = ::librum::error::EnumEncodeError<#repr, ::librum::error::GenericEncodeError>; type Error = ::oct::error::EnumEncodeError<#repr, ::oct::error::GenericEncodeError>;
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
#[inline] #[inline]
fn encode(&self, stream: &mut ::librum::OStream) -> ::core::result::Result<(), Self::Error> { fn encode(&self, stream: &mut ::oct::encode::Output) -> ::core::result::Result<(), Self::Error> {
match *self { match *self {
#( #(
#patterns => { #patterns => {
<#repr as ::librum::Encode>::encode(&#discriminants, stream) <#repr as ::oct::encode::Encode>::encode(&#discriminants, stream)
.map_err(::librum::error::EnumEncodeError::Discriminant)?; .map_err(::oct::error::EnumEncodeError::BadDiscriminant)?;
#( #(
::librum::Encode::encode(#captures, stream) ::oct::encode::Encode::encode(#captures, stream)
.map_err(::core::convert::Into::<::librum::error::GenericEncodeError>::into) .map_err(::core::convert::Into::<::oct::error::GenericEncodeError>::into)
.map_err(::librum::error::EnumEncodeError::Field)?; .map_err(::oct::error::EnumEncodeError::BadField)?;
)* )*
} }
)* )*

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
@ -48,15 +48,15 @@ pub fn encode_struct(data: DataStruct) -> TokenStream {
}; };
quote! { quote! {
type Error = ::librum::error::GenericEncodeError; type Error = ::oct::error::GenericEncodeError;
#[inline] #[inline]
fn encode(&self, stream: &mut ::librum::OStream) -> ::core::result::Result<(), Self::Error> { fn encode(&self, stream: &mut ::oct::encode::Output) -> ::core::result::Result<(), Self::Error> {
let #pattern = self; let #pattern = self;
#( #(
::librum::Encode::encode(#captures, stream) ::oct::encode::Encode::encode(#captures, stream)
.map_err(::core::convert::Into::<::librum::error::GenericEncodeError>::into)?; .map_err(::core::convert::Into::<::oct::error::GenericEncodeError>::into)?;
)* )*
::core::result::Result::Ok(()) ::core::result::Result::Ok(())

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::use_mod; use crate::use_mod;

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::Repr; use crate::Repr;
@ -48,7 +48,7 @@ pub fn sized_encode_enum(data: DataEnum, repr: Repr) -> TokenStream {
let mut current_size = 0x0usize; let mut current_size = 0x0usize;
#( #(
current_size = 0x0 #(+ <#tys as ::librum::SizedEncode>::MAX_ENCODED_SIZE)*; current_size = 0x0 #(+ <#tys as ::oct::encode::SizedEncode>::MAX_ENCODED_SIZE)*;
if current_size > total_size { total_size = current_size }; if current_size > total_size { total_size = current_size };
)* )*

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
@ -31,6 +31,6 @@ pub fn sized_encode_struct(data: DataStruct) -> TokenStream {
.collect(); .collect();
quote! { quote! {
const MAX_ENCODED_SIZE: usize = 0x0 #( + <#tys as ::librum::SizedEncode>::MAX_ENCODED_SIZE)*; const MAX_ENCODED_SIZE: usize = 0x0 #( + <#tys as ::oct::encode::SizedEncode>::MAX_ENCODED_SIZE)*;
} }
} }

View file

@ -1,30 +1,30 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
#![doc(html_logo_url = "https://gitlab.com/bjoernager/librum/-/raw/master/doc-icon.svg")] #![doc(html_logo_url = "https://gitlab.com/bjoernager/oct/-/raw/master/doc-icon.svg")]
//! This crate implements procedural macros for [`Librum`](https://crates.io/crates/librum/). //! This crate implements procedural macros for [`oct`](https://crates.io/crates/oct/).
// For use in macros: // For use in macros:
extern crate self as librum_macros; extern crate self as oct_macros;
macro_rules! use_mod { macro_rules! use_mod {
($vis:vis $name:ident) => { ($vis:vis $name:ident) => {
@ -51,7 +51,7 @@ pub fn derive_decode(input: TokenStream) -> TokenStream {
let output = impl_derive_macro( let output = impl_derive_macro(
input, input,
parse2(quote! { ::librum::Decode }).unwrap(), parse2(quote! { ::oct::decode::Decode }).unwrap(),
None, None,
impls::decode_struct, impls::decode_struct,
impls::decode_enum, impls::decode_enum,
@ -68,7 +68,7 @@ pub fn derive_encode(input: TokenStream) -> TokenStream {
let output = impl_derive_macro( let output = impl_derive_macro(
input, input,
parse2(quote! { ::librum::Encode }).unwrap(), parse2(quote! { ::oct::encode::Encode }).unwrap(),
None, None,
impls::encode_struct, impls::encode_struct,
impls::encode_enum, impls::encode_enum,
@ -85,7 +85,7 @@ pub fn derive_sized_encode(input: TokenStream) -> TokenStream {
let output = impl_derive_macro( let output = impl_derive_macro(
input, input,
parse2(quote! { ::librum::SizedEncode }).unwrap(), parse2(quote! { ::oct::encode::SizedEncode }).unwrap(),
None, None,
impls::sized_encode_struct, impls::sized_encode_struct,
impls::sized_encode_enum, impls::sized_encode_enum,

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
@ -61,22 +61,20 @@ impl Repr {
for attr in attrs { for attr in attrs {
if attr.path().is_ident("repr") { if attr.path().is_ident("repr") {
attr.parse_nested_meta(|meta| { attr.parse_nested_meta(|meta| {
use Repr::*;
let ident = meta.path.require_ident()?; let ident = meta.path.require_ident()?;
if ident == "u8" { this = Some(U8) } if ident == "u8" { this = Some(Self::U8) }
else if ident == "i8" { this = Some(I8) } else if ident == "i8" { this = Some(Self::I8) }
else if ident == "u16" { this = Some(U16) } else if ident == "u16" { this = Some(Self::U16) }
else if ident == "i16" { this = Some(I16) } else if ident == "i16" { this = Some(Self::I16) }
else if ident == "u32" { this = Some(U32) } else if ident == "u32" { this = Some(Self::U32) }
else if ident == "i32" { this = Some(I32) } else if ident == "i32" { this = Some(Self::I32) }
else if ident == "u64" { this = Some(U64) } else if ident == "u64" { this = Some(Self::U64) }
else if ident == "i64" { this = Some(I64) } else if ident == "i64" { this = Some(Self::I64) }
else if ident == "u128" { this = Some(U128) } else if ident == "u128" { this = Some(Self::U128) }
else if ident == "i128" { this = Some(I128) } else if ident == "i128" { this = Some(Self::I128) }
else if ident == "usize" { this = Some(Usize) } else if ident == "usize" { this = Some(Self::Usize) }
else if ident == "isize" { this = Some(Isize) } else if ident == "isize" { this = Some(Self::Isize) }
else { panic!("`{ident}` is not a derivable enumeration representation") }; else { panic!("`{ident}` is not a derivable enumeration representation") };
Ok(()) Ok(())
@ -92,21 +90,19 @@ impl Repr {
#[inline] #[inline]
#[must_use] #[must_use]
pub const fn to_str(self) -> &'static str { pub const fn to_str(self) -> &'static str {
use Repr::*;
match self { match self {
U8 => "u8", Self::U8 => "u8",
I8 => "i8", Self::I8 => "i8",
U16 => "u16", Self::U16 => "u16",
I16 => "i16", Self::I16 => "i16",
U32 => "u32", Self::U32 => "u32",
I32 => "i32", Self::I32 => "i32",
U64 => "u64", Self::U64 => "u64",
I64 => "i64", Self::I64 => "i64",
U128 => "u128", Self::U128 => "u128",
I128 => "i128", Self::I128 => "i128",
Usize => "usize", Self::Usize => "usize",
Isize => "isize", Self::Isize => "isize",
} }
} }

18
oct.svg Normal file
View file

@ -0,0 +1,18 @@
<svg height="112" width="112" xmlns="http://www.w3.org/2000/svg">
<mask id="tHorizontalArm">
<rect fill="white" height="100%" width="100%" x="0" y="0" />
<circle cx="56" cy="56" fill="none" r="32" stroke="black" stroke-width="20" />
</mask>
<mask id="glyph">
<!-- O: -->
<circle cx="56" cy="56" fill="none" r="32" stroke="white" stroke-width="16" />
<!-- T: -->
<rect fill="white" height="16" paint-order="stroke" stroke="black" stroke-width="4" width="96" x="8" y="48" />
<rect fill="white" height="96" mask="url(#tHorizontalArm)" width="16" x="48" y="8" />
</mask>
<rect fill="#02764A" height="100%" width="100%" x="0" y="0" /> <!-- oklch(50% 0.115300 158.520) -->
<rect fill="#FFFFFF" height="100%" mask="url(#glyph)" width="100%" x="0" y="0" />
</svg>

After

Width:  |  Height:  |  Size: 779 B

View file

@ -1,9 +1,9 @@
[package] [package]
name = "librum" name = "oct"
version = "0.13.1" version = "0.14.0"
edition = "2021" edition = "2021"
rust-version = "1.83" rust-version = "1.83"
documentation = "https://docs.rs/librum/" documentation = "https://docs.rs/oct/"
authors.workspace = true authors.workspace = true
description.workspace = true description.workspace = true
@ -21,11 +21,11 @@ all-features = true
default = ["alloc", "proc-macro", "std"] default = ["alloc", "proc-macro", "std"]
alloc = [] alloc = []
proc-macro = ["librum-macros"] proc-macro = ["oct-macros"]
std = [] std = []
[dependencies] [dependencies]
librum-macros = { path = "../librum-macros", version = "0.13.0", optional = true} oct-macros = { path = "../oct-macros", version = "0.14.0", optional = true}
[lints] [lints]
workspace = true workspace = true

View file

@ -1,30 +1,29 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::{DecodeBorrowed, IStream, SizedEncode}; use crate::decode::{DecodeBorrowed, Input};
use crate::error::{ use crate::error::{
BoolDecodeError,
CStringDecodeError, CStringDecodeError,
CharDecodeError, CharDecodeError,
CollectionDecodeError, CollectionDecodeError,
@ -104,12 +103,12 @@ pub trait Decode: Sized {
/// The type returned in case of error. /// The type returned in case of error.
type Error; type Error;
/// Decodes an object from the provided stream. /// Decodes an object from the provided input.
/// ///
/// # Errors /// # Errors
/// ///
/// If decoding fails due to e.g. an invalid byte sequence in the stream, then an error should be returned. /// If decoding fails due to e.g. an invalid byte sequence in the input, then an error should be returned.
fn decode(stream: &mut IStream) -> Result<Self, Self::Error>; fn decode(input: &mut Input) -> Result<Self, Self::Error>;
} }
/// Implemented for tuples with up to twelve members. /// Implemented for tuples with up to twelve members.
@ -118,9 +117,9 @@ impl<T: Decode> Decode for (T, ) {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let this = (Decode::decode(stream)?, ); let this = (Decode::decode(input)?, );
Ok(this) Result::Ok(this)
} }
} }
@ -128,14 +127,14 @@ impl<T: Decode, const N: usize> Decode for [T; N] {
type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, T::Error>>; type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, T::Error>>;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
// Initialise the array incrementally. // Initialise the array incrementally.
let mut buf: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut buf = [const { MaybeUninit::<T>::uninit() }; N];
for (i, item) in buf.iter_mut().enumerate() { for (i, item) in buf.iter_mut().enumerate() {
let value = Decode::decode(stream) let value = Decode::decode(input)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?; .map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
item.write(value); item.write(value);
} }
@ -148,7 +147,7 @@ impl<T: Decode, const N: usize> Decode for [T; N] {
// be used here, and `transmute_unchecked` is re- // be used here, and `transmute_unchecked` is re-
// served for the greedy rustc devs. // served for the greedy rustc devs.
let this = unsafe { buf.as_ptr().cast::<[T; N]>().read() }; let this = unsafe { buf.as_ptr().cast::<[T; N]>().read() };
Ok(this) Result::Ok(this)
} }
} }
@ -158,26 +157,26 @@ impl<T: Decode> Decode for Arc<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?; let value = Decode::decode(input)?;
let this = Self::new(value); let this = Self::new(value);
Ok(this) Result::Ok(this)
} }
} }
impl Decode for bool { impl Decode for bool {
type Error = BoolDecodeError; type Error = Infallible;
/// Lossily reinterprets a byte value as a boolean.
///
/// Whilst <code>[Encode](crate::encode::Encode)::[encode](crate::encode::Encode::encode)</code> will only yield the values `0` and `1`, this method clamps all values above `1`.
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = u8::decode(stream).unwrap(); let Ok(value) = u8::decode(input);
match value { let this = value != 0x0;
0x0 => Ok(false), Result::Ok(this)
0x1 => Ok(true),
_ => Err(BoolDecodeError { value })
}
} }
} }
@ -185,20 +184,20 @@ impl<T: Decode> Decode for Bound<T> {
type Error = EnumDecodeError<u8, T::Error>; type Error = EnumDecodeError<u8, T::Error>;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let discriminant = u8::decode(stream).unwrap(); let Ok(discriminant) = u8::decode(input);
let this = match discriminant { let this = match discriminant {
0x0 => { 0x0 => {
let bound = Decode::decode(stream) let bound = Decode::decode(input)
.map_err(EnumDecodeError::Field)?; .map_err(EnumDecodeError::BadField)?;
Self::Included(bound) Self::Included(bound)
} }
0x1 => { 0x1 => {
let bound = Decode::decode(stream) let bound = Decode::decode(input)
.map_err(EnumDecodeError::Field)?; .map_err(EnumDecodeError::BadField)?;
Self::Excluded(bound) Self::Excluded(bound)
} }
@ -208,7 +207,7 @@ impl<T: Decode> Decode for Bound<T> {
value => return Err(EnumDecodeError::UnassignedDiscriminant { value }), value => return Err(EnumDecodeError::UnassignedDiscriminant { value }),
}; };
Ok(this) Result::Ok(this)
} }
} }
@ -218,11 +217,11 @@ impl<T: Decode> Decode for Box<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?; let value = Decode::decode(input)?;
let this = Self::new(value); let this = Self::new(value);
Ok(this) Result::Ok(this)
} }
} }
@ -230,11 +229,11 @@ impl<T: Decode> Decode for Cell<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?; let value = Decode::decode(input)?;
let this = Self::new(value); let this = Self::new(value);
Ok(this) Result::Ok(this)
} }
} }
@ -242,14 +241,17 @@ impl Decode for char {
type Error = CharDecodeError; type Error = CharDecodeError;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let code_point = u32::decode(stream).unwrap(); let Ok(code_point) = u32::decode(input);
let this = code_point match code_point {
.try_into() code_point @ (0x0000..=0xD7FF | 0xDE00..=0x10FFFF) => {
.map_err(|_| CharDecodeError { code_point })?; let this = unsafe { Self::from_u32_unchecked(code_point) };
Result::Ok(this)
},
Ok(this) code_point => Err(CharDecodeError { code_point }),
}
} }
} }
@ -263,11 +265,11 @@ where
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?; let value = Decode::decode(input)?;
let this = Self::Owned(value); let this = Self::Owned(value);
Ok(this) Result::Ok(this)
} }
} }
@ -277,10 +279,10 @@ impl Decode for CString {
type Error = CStringDecodeError; type Error = CStringDecodeError;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap(); let Ok(len) = Decode::decode(input);
let data = stream.read(len); let data = input.read(len).unwrap();
for (i, c) in data.iter().enumerate() { for (i, c) in data.iter().enumerate() {
if *c == b'\x00' { return Err(CStringDecodeError { index: i }) }; if *c == b'\x00' { return Err(CStringDecodeError { index: i }) };
@ -298,7 +300,7 @@ impl Decode for CString {
// SAFETY: We have already tested the data. // SAFETY: We have already tested the data.
let this = unsafe { Self::from_vec_unchecked(buf) }; let this = unsafe { Self::from_vec_unchecked(buf) };
Ok(this) Result::Ok(this)
} }
} }
@ -306,12 +308,12 @@ impl Decode for Duration {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let secs = Decode::decode(stream)?; let Ok(secs) = Decode::decode(input);
let nanos = Decode::decode(stream)?; let Ok(nanos) = Decode::decode(input);
let this = Self::new(secs, nanos); let this = Self::new(secs, nanos);
Ok(this) Result::Ok(this)
} }
} }
@ -326,22 +328,22 @@ where
type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, E>>; type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, E>>;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap(); let Ok(len) = Decode::decode(input);
let mut this = Self::with_capacity_and_hasher(len, Default::default()); let mut this = Self::with_capacity_and_hasher(len, Default::default());
for i in 0x0..len { for i in 0x0..len {
let key= Decode::decode(stream) let key= Decode::decode(input)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?; .map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
let value = Decode::decode(stream) let value = Decode::decode(input)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?; .map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
this.insert(key, value); this.insert(key, value);
} }
Ok(this) Result::Ok(this)
} }
} }
@ -355,19 +357,19 @@ where
type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, K::Error>>; type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, K::Error>>;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap(); let Ok(len) = Decode::decode(input);
let mut this = Self::with_capacity_and_hasher(len, Default::default()); let mut this = Self::with_capacity_and_hasher(len, Default::default());
for i in 0x0..len { for i in 0x0..len {
let key = Decode::decode(stream) let key = Decode::decode(input)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }) )?; .map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }) )?;
this.insert(key); this.insert(key);
} }
Ok(this) Result::Ok(this)
} }
} }
@ -375,7 +377,7 @@ impl Decode for Infallible {
type Error = Self; type Error = Self;
#[inline(always)] #[inline(always)]
fn decode(_stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(_input: &mut Input) -> Result<Self, Self::Error> {
panic!("cannot deserialise `Infallible` as it cannot be serialised to begin with") panic!("cannot deserialise `Infallible` as it cannot be serialised to begin with")
} }
} }
@ -384,18 +386,18 @@ impl Decode for IpAddr {
type Error = EnumDecodeError<u8, Infallible>; type Error = EnumDecodeError<u8, Infallible>;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let discriminant = u8::decode(stream) let discriminant = u8::decode(input)
.map_err(EnumDecodeError::InvalidDiscriminant)?; .map_err(EnumDecodeError::InvalidDiscriminant)?;
let this = match discriminant { let this = match discriminant {
0x4 => Self::V4(Decode::decode(stream).unwrap()), 0x4 => Self::V4(Decode::decode(input).unwrap()),
0x6 => Self::V6(Decode::decode(stream).unwrap()), 0x6 => Self::V6(Decode::decode(input).unwrap()),
value => return Err(EnumDecodeError::UnassignedDiscriminant { value }) value => return Err(EnumDecodeError::UnassignedDiscriminant { value })
}; };
Ok(this) Result::Ok(this)
} }
} }
@ -403,9 +405,11 @@ impl Decode for Ipv4Addr {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?; let Ok(value) = Decode::decode(input);
Ok(Self::from_bits(value))
let this = Self::from_bits(value);
Result::Ok(this)
} }
} }
@ -413,9 +417,11 @@ impl Decode for Ipv6Addr {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?; let Ok(value) = Decode::decode(input);
Ok(Self::from_bits(value))
let this = Self::from_bits(value);
Result::Ok(this)
} }
} }
@ -423,9 +429,10 @@ impl Decode for isize {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = i16::decode(stream)?; let Ok(value) = i16::decode(input);
Ok(value as Self)
Result::Ok(value as Self)
} }
} }
@ -435,19 +442,19 @@ impl<T: Decode> Decode for LinkedList<T> {
type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, T::Error>>; type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, T::Error>>;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let len = usize::decode(stream).unwrap(); let Ok(len) = usize::decode(input);
let mut this = Self::new(); let mut this = Self::new();
for i in 0x0..len { for i in 0x0..len {
let value = T::decode(stream) let value = T::decode(input)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?; .map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
this.push_back(value); this.push_back(value);
} }
Ok(this) Result::Ok(this)
} }
} }
@ -457,8 +464,11 @@ impl<T: Decode> Decode for Mutex<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
Ok(Self::new(Decode::decode(stream)?)) let value = Decode::decode(input)?;
let this = Self::new(value);
Result::Ok(this)
} }
} }
@ -467,16 +477,17 @@ impl<T: Decode> Decode for Option<T> {
#[expect(clippy::if_then_some_else_none)] // ??? #[expect(clippy::if_then_some_else_none)] // ???
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let sign = bool::decode(stream).unwrap(); let sign = bool::decode(input)
.map_err::<T::Error, _>(|_e| unreachable!())?;
let this = if sign { let this = if sign {
Some(Decode::decode(stream)?) Some(Decode::decode(input)?)
} else { } else {
None None
}; };
Ok(this) Result::Ok(this)
} }
} }
@ -484,8 +495,8 @@ impl<T> Decode for PhantomData<T> {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn decode(_stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(_input: &mut Input) -> Result<Self, Self::Error> {
Ok(Self) Result::Ok(Self)
} }
} }
@ -493,8 +504,8 @@ impl Decode for PhantomPinned {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn decode(_stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(_input: &mut Input) -> Result<Self, Self::Error> {
Ok(Self) Result::Ok(Self)
} }
} }
@ -502,11 +513,11 @@ impl<T: Decode> Decode for Range<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let start = Decode::decode(stream)?; let start = Decode::decode(input)?;
let end = Decode::decode(stream)?; let end = Decode::decode(input)?;
Ok(start..end) Result::Ok(start..end)
} }
} }
@ -514,10 +525,10 @@ impl<T: Decode> Decode for RangeFrom<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let start = Decode::decode(stream)?; let start = Decode::decode(input)?;
Ok(start..) Result::Ok(start..)
} }
} }
@ -525,8 +536,8 @@ impl Decode for RangeFull {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn decode(_stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(_input: &mut Input) -> Result<Self, Self::Error> {
Ok(..) Result::Ok(..)
} }
} }
@ -534,11 +545,11 @@ impl<T: Decode> Decode for RangeInclusive<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let start = Decode::decode(stream)?; let start = Decode::decode(input)?;
let end = Decode::decode(stream)?; let end = Decode::decode(input)?;
Ok(start..=end) Result::Ok(start..=end)
} }
} }
@ -546,10 +557,10 @@ impl<T: Decode> Decode for RangeTo<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let end = Decode::decode(stream)?; let end = Decode::decode(input)?;
Ok(..end) Result::Ok(..end)
} }
} }
@ -557,10 +568,10 @@ impl<T: Decode> Decode for RangeToInclusive<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let end = Decode::decode(stream)?; let end = Decode::decode(input)?;
Ok(..=end) Result::Ok(..=end)
} }
} }
@ -570,8 +581,8 @@ impl<T: Decode> Decode for Rc<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
Ok(Self::new(Decode::decode(stream)?)) Result::Ok(Self::new(Decode::decode(input)?))
} }
} }
@ -579,15 +590,15 @@ impl<T: Decode> Decode for RefCell<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?; let value = Decode::decode(input)?;
let this = Self::new(value); let this = Self::new(value);
Ok(this) Result::Ok(this)
} }
} }
impl<T, E, Err> Decode for core::result::Result<T, E> impl<T, E, Err> Decode for Result<T, E>
where where
T: Decode<Error = Err>, T: Decode<Error = Err>,
E: Decode<Error = Err>, E: Decode<Error = Err>,
@ -595,23 +606,23 @@ where
type Error = EnumDecodeError<bool, Err>; type Error = EnumDecodeError<bool, Err>;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let sign = bool::decode(stream) let sign = bool::decode(input)
.map_err(EnumDecodeError::InvalidDiscriminant)?; .map_err(EnumDecodeError::InvalidDiscriminant)?;
let this = if sign { let this = if sign {
let value = Decode::decode(stream) let value = Decode::decode(input)
.map_err(EnumDecodeError::Field)?; .map_err(EnumDecodeError::BadField)?;
Err(value) Err(value)
} else { } else {
let value = Decode::decode(stream) let value = Decode::decode(input)
.map_err(EnumDecodeError::Field)?; .map_err(EnumDecodeError::BadField)?;
Ok(value) Ok(value)
}; };
Ok(this) Result::Ok(this)
} }
} }
@ -621,11 +632,11 @@ impl<T: Decode> Decode for RwLock<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?; let value = Decode::decode(input)?;
let this = Self::new(value); let this = Self::new(value);
Ok(this) Result::Ok(this)
} }
} }
@ -633,11 +644,11 @@ impl<T: Decode> Decode for Saturating<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?; let value = Decode::decode(input)?;
let this = Self(value); let this = Self(value);
Ok(this) Result::Ok(this)
} }
} }
@ -645,17 +656,15 @@ impl Decode for SocketAddr {
type Error = EnumDecodeError<u8, Infallible>; type Error = EnumDecodeError<u8, Infallible>;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let discriminant = u8::decode(stream).unwrap(); let Ok(discriminant) = u8::decode(input);
let this = match discriminant { match discriminant {
0x4 => Self::V4(Decode::decode(stream).unwrap()), 0x4 => Result::Ok(Self::V4(Decode::decode(input).unwrap())),
0x6 => Self::V6(Decode::decode(stream).unwrap()), 0x6 => Result::Ok(Self::V6(Decode::decode(input).unwrap())),
value => return Err(EnumDecodeError::UnassignedDiscriminant { value }) value => Err(EnumDecodeError::UnassignedDiscriminant { value }),
}; }
Ok(this)
} }
} }
@ -663,12 +672,12 @@ impl Decode for SocketAddrV4 {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let ip = Decode::decode(stream)?; let ip = Decode::decode(input)?;
let port = Decode::decode(stream)?; let port = Decode::decode(input)?;
let this = Self::new(ip, port); let this = Self::new(ip, port);
Ok(this) Result::Ok(this)
} }
} }
@ -676,14 +685,14 @@ impl Decode for SocketAddrV6 {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let ip = Decode::decode(stream)?; let ip = Decode::decode(input)?;
let port = Decode::decode(stream)?; let port = Decode::decode(input)?;
let flow_info = Decode::decode(stream)?; let flow_info = Decode::decode(input)?;
let scope_id = Decode::decode(stream)?; let scope_id = Decode::decode(input)?;
let this = Self::new(ip, port, flow_info, scope_id); let this = Self::new(ip, port, flow_info, scope_id);
Ok(this) Result::Ok(this)
} }
} }
@ -693,18 +702,21 @@ impl Decode for String {
type Error = CollectionDecodeError<Infallible, Utf8Error>; type Error = CollectionDecodeError<Infallible, Utf8Error>;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap(); let Ok(len) = Decode::decode(input);
let data = stream.read(len); let data = input.read(len).unwrap();
str::from_utf8(data) if let Err(e) = str::from_utf8(data) {
.map_err(|e| {
let i = e.valid_up_to(); let i = e.valid_up_to();
let c = data[i]; let c = data[i];
CollectionDecodeError::Item(Utf8Error { value: c, index: i }) return Err(
})?; CollectionDecodeError::BadItem(
Utf8Error { value: c, index: i },
),
);
};
let mut v = Vec::with_capacity(len); let mut v = Vec::with_capacity(len);
@ -718,7 +730,7 @@ impl Decode for String {
// SAFETY: We have already tested the raw data. // SAFETY: We have already tested the raw data.
let this = unsafe { Self::from_utf8_unchecked(v) }; let this = unsafe { Self::from_utf8_unchecked(v) };
Ok(this) Result::Ok(this)
} }
} }
@ -728,8 +740,8 @@ impl Decode for SystemTime {
type Error = SystemTimeDecodeError; type Error = SystemTimeDecodeError;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let time = i64::decode(stream).unwrap(); let Ok(time) = i64::decode(input);
let this = if time.is_positive() { let this = if time.is_positive() {
let time = time as u64; let time = time as u64;
@ -749,8 +761,8 @@ impl Decode for () {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn decode(_stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(_input: &mut Input) -> Result<Self, Self::Error> {
Ok(()) Result::Ok(())
} }
} }
@ -758,9 +770,9 @@ impl Decode for usize {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = u16::decode(stream)?; let value = u16::decode(input)?;
Ok(value as Self) Result::Ok(value as Self)
} }
} }
@ -770,15 +782,15 @@ impl<T: Decode> Decode for Vec<T> {
type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, T::Error>>; type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, T::Error>>;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap(); let Ok(len) = Decode::decode(input);
let mut this = Self::with_capacity(len); let mut this = Self::with_capacity(len);
let buf = this.as_mut_ptr(); let buf = this.as_mut_ptr();
for i in 0x0..len { for i in 0x0..len {
let value = Decode::decode(stream) let value = Decode::decode(input)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?; .map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
// SAFETY: Each index is within bounds (i.e. capac- // SAFETY: Each index is within bounds (i.e. capac-
// ity). // ity).
@ -788,7 +800,7 @@ impl<T: Decode> Decode for Vec<T> {
// SAFETY: We have initialised the buffer. // SAFETY: We have initialised the buffer.
unsafe { this.set_len(len); } unsafe { this.set_len(len); }
Ok(this) Result::Ok(this)
} }
} }
@ -796,26 +808,26 @@ impl<T: Decode> Decode for Wrapping<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?; let value = Decode::decode(input)?;
let this = Self(value); let this = Self(value);
Ok(this) Result::Ok(this)
} }
} }
macro_rules! impl_numeric { macro_rules! impl_numeric {
($ty:ty$(,)?) => { ($ty:ty$(,)?) => {
impl ::librum::Decode for $ty { impl ::oct::decode::Decode for $ty {
type Error = ::core::convert::Infallible; type Error = ::core::convert::Infallible;
#[inline] #[inline]
fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result<Self, Self::Error> { fn decode(input: &mut ::oct::decode::Input) -> ::core::result::Result<Self, Self::Error> {
let mut data = [::core::default::Default::default(); Self::MAX_ENCODED_SIZE]; let mut data = [::core::default::Default::default(); <Self as ::oct::encode::SizedEncode>::MAX_ENCODED_SIZE];
stream.read_into(&mut data); input.read_into(&mut data).unwrap();
let this = Self::from_le_bytes(data); let this = Self::from_le_bytes(data);
Ok(this) ::core::result::Result::Ok(this)
} }
} }
}; };
@ -826,19 +838,19 @@ macro_rules! impl_tuple {
$($tys:ident),+$(,)? $($tys:ident),+$(,)?
} => { } => {
#[doc(hidden)] #[doc(hidden)]
impl<$($tys, )* E> ::librum::Decode for ($($tys, )*) impl<$($tys, )* E> ::oct::decode::Decode for ($($tys, )*)
where where
$($tys: Decode<Error = E>, )* $($tys: Decode<Error = E>, )*
{ {
type Error = E; type Error = E;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result<Self, Self::Error> { fn decode(input: &mut ::oct::decode::Input) -> ::core::result::Result<Self, Self::Error> {
let this = ( let this = (
$( <$tys as ::librum::Decode>::decode(stream)?, )* $( <$tys as ::oct::decode::Decode>::decode(input)?, )*
); );
Ok(this) ::core::result::Result::Ok(this)
} }
} }
}; };
@ -846,17 +858,23 @@ macro_rules! impl_tuple {
macro_rules! impl_non_zero { macro_rules! impl_non_zero {
($ty:ty$(,)?) => { ($ty:ty$(,)?) => {
impl ::librum::Decode for ::core::num::NonZero<$ty> { impl ::oct::decode::Decode for ::core::num::NonZero<$ty> {
type Error = ::librum::error::NonZeroDecodeError; type Error = ::oct::error::NonZeroDecodeError;
#[inline] #[inline]
fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result<Self, Self::Error> { fn decode(input: &mut ::oct::decode::Input) -> ::core::result::Result<Self, Self::Error> {
let Ok(value) = <$ty as ::librum::Decode>::decode(stream); use ::core::result::Result;
let this = ::core::num::NonZero::new(value) let Result::Ok(value) = <$ty as ::oct::decode::Decode>::decode(input);
.ok_or(::librum::error::NonZeroDecodeError)?;
Ok(this) match value {
0x0 => Result::Err(::oct::error::NonZeroDecodeError),
value => {
let this = unsafe { ::core::num::NonZero::new_unchecked(value) };
Result::Ok(this)
},
}
} }
} }
}; };
@ -870,15 +888,15 @@ macro_rules! impl_atomic {
} => { } => {
#[cfg(target_has_atomic = $width)] #[cfg(target_has_atomic = $width)]
#[cfg_attr(doc, doc(cfg(target_has_atomic = $width)))] #[cfg_attr(doc, doc(cfg(target_has_atomic = $width)))]
impl ::librum::Decode for $atomic_ty { impl ::oct::decode::Decode for $atomic_ty {
type Error = <$ty as ::librum::Decode>::Error; type Error = <$ty as ::oct::decode::Decode>::Error;
#[inline(always)] #[inline(always)]
fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result<Self, Self::Error> { fn decode(input: &mut ::oct::decode::Input) -> ::core::result::Result<Self, Self::Error> {
let value = ::librum::Decode::decode(stream)?; let value = ::oct::decode::Decode::decode(input)?;
let this = Self::new(value); let this = Self::new(value);
Ok(this) ::core::result::Result::Ok(this)
} }
} }
}; };

View file

@ -1,32 +1,33 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use librum::{Decode, Encode, IStream, SizedEncode}; use oct::decode::{Decode, Input};
use oct::encode::{Encode, SizedEncode};
use std::char; use std::char;
use std::vec::Vec; use std::vec::Vec;
use std::string::String; use std::string::String;
macro_rules! test { macro_rules! test {
($ty:ty: $data:expr => $value:expr) => {{ ($ty:ty: $data:expr => $value:expr) => {{
let mut stream = IStream::new(&$data); let mut stream = Input::new(&$data);
let left = <$ty as Decode>::decode(&mut stream).unwrap(); let left = <$ty as Decode>::decode(&mut stream).unwrap();
let right = $value; let right = $value;
@ -101,6 +102,7 @@ fn test_decode_derive() {
Unnamed(i32), Unnamed(i32),
Named { timestamp: u64 }, Named { timestamp: u64 },
} }
test!(ProcExit: [ test!(ProcExit: [
0x01, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x0B, 0x5E, 0x01, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x0B, 0x5E,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

View file

@ -1,25 +1,25 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::Decode; use crate::decode::Decode;
use core::borrow::Borrow; use core::borrow::Borrow;
@ -45,7 +45,7 @@ use alloc::sync::Arc;
/// ///
/// Implementing this trait is specifically a promise that <code>&lt;Self as [Decode]&gt;::[decode](Decode::decode)</code> can handle any encoding of `B`. /// Implementing this trait is specifically a promise that <code>&lt;Self as [Decode]&gt;::[decode](Decode::decode)</code> can handle any encoding of `B`.
/// ///
/// This trait is mainly useful for types that implement [`Encode`](crate::Encode::encode) but do not implement `Decode` for whatever reason (mostly due to being unsized). /// This trait is mainly useful for types that implement [`Encode`](crate::encode::Encode::encode) but do not implement `Decode` for whatever reason (mostly due to being unsized).
/// The primary user of this trait is the `Decode` implementation of [`Cow`](alloc::borrow::Cow). /// The primary user of this trait is the `Decode` implementation of [`Cow`](alloc::borrow::Cow).
/// ///
/// # Arrays /// # Arrays

View file

@ -19,16 +19,18 @@
// er General Public License along with Librum. If // er General Public License along with Librum. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::error::InputError;
use core::ptr::copy_nonoverlapping; use core::ptr::copy_nonoverlapping;
use core::slice; use core::slice;
/// Byte stream suitable for input. /// Byte stream suitable for reading.
pub struct IStream<'a> { pub struct Input<'a> {
buf: &'a [u8], buf: &'a [u8],
pos: usize, pos: usize,
} }
impl<'a> IStream<'a> { impl<'a> Input<'a> {
/// Constructs a new i-stream. /// Constructs a new i-stream.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
@ -44,15 +46,16 @@ impl<'a> IStream<'a> {
/// ///
/// If the requested amount of bytes could not exactly be read, then this method will panic. /// If the requested amount of bytes could not exactly be read, then this method will panic.
#[inline] #[inline]
pub fn read(&mut self, count: usize) -> &'a [u8] { pub const fn read(&mut self, count: usize) -> Result<&'a [u8], InputError> {
let remaining = self.buf.len() - self.pos; let remaining = self.buf.len() - self.pos;
assert!( if remaining < count {
remaining >= count, return Err(InputError {
"cannot read ({count}) bytes at ({}) from stream with capacity of ({})", capacity: self.buf.len(),
self.pos, position: self.pos,
self.buf.len(), count,
); });
}
let data = unsafe { let data = unsafe {
let ptr = self.buf.as_ptr().add(self.pos); let ptr = self.buf.as_ptr().add(self.pos);
@ -62,7 +65,7 @@ impl<'a> IStream<'a> {
self.pos += count; self.pos += count;
data Ok(data)
} }
/// Reads bytes from the stream into a predefined buffer. /// Reads bytes from the stream into a predefined buffer.
@ -73,16 +76,17 @@ impl<'a> IStream<'a> {
/// ///
/// If the provided buffer could not be completely filled, then this method will panic. /// If the provided buffer could not be completely filled, then this method will panic.
#[inline] #[inline]
pub fn read_into(&mut self, buf: &mut [u8]) { pub const fn read_into(&mut self, buf: &mut [u8]) -> Result<(), InputError> {
let count = buf.len(); let count = buf.len();
let remaining = self.buf.len() - self.pos; let remaining = self.remaining();
assert!( if remaining < count {
remaining >= count, return Err(InputError {
"cannot read ({count}) bytes at ({}) from stream with capacity of ({})", capacity: self.buf.len(),
self.pos, position: self.pos,
self.buf.len(), count,
); });
}
unsafe { unsafe {
let src = self.buf.as_ptr().add(self.pos); let src = self.buf.as_ptr().add(self.pos);
@ -92,15 +96,30 @@ impl<'a> IStream<'a> {
} }
self.pos += count; self.pos += count;
Ok(())
} }
/// Closes the stream. /// Retrieves the maximum capacity of the input stream.
///
/// The total ammount of bytes read is returned.
#[inline(always)] #[inline(always)]
pub const fn close(self) -> usize { #[must_use]
let Self { pos, .. } = self; pub const fn capacity(&self) -> usize {
self.buf.len()
}
pos /// Retrieves the remaining, free capacity of the input stream.
#[inline(always)]
#[must_use]
pub const fn remaining(&self) -> usize {
// SAFETY: The cursor position can never exceed the
// stream's capacity.
unsafe { self.capacity().unchecked_sub(self.position()) }
}
/// Retrieves the current cursor position of the input stream.
#[inline(always)]
#[must_use]
pub const fn position(&self) -> usize {
self.pos
} }
} }

39
oct/src/decode/mod.rs Normal file
View file

@ -0,0 +1,39 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
// This file is part of oct.
//
// oct 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.
//
// oct 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 oct. If
// not, see <https://www.gnu.org/licenses/>.
//! Error variants.
//!
//! This module defines the error types used by oct.
//! All of these types define (at least conditionally) the [`Error`](core::error::Error) trait.
use crate::use_mod;
use_mod!(pub decode);
use_mod!(pub decode_borrowed);
use_mod!(pub input);
/// Implements [`Decode`] for the provided type.
///
/// This macro assumes the same format used by the equivalent [`Encode`](derive@crate::encode::Encode) macro.
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc, doc(cfg(feature = "proc-macro")))]
#[doc(inline)]
pub use oct_macros::Decode;

View file

@ -1,28 +1,28 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::OStream; use crate::encode::Output;
use crate::error::{ use crate::error::{
CollectionEncodeError, CollectionEncodeError,
EnumEncodeError, EnumEncodeError,
@ -96,7 +96,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
/// It is recommended to simply derive this trait for custom types. /// It is recommended to simply derive this trait for custom types.
/// It can, of course, also just be manually implemented. /// It can, of course, also just be manually implemented.
/// ///
/// If all possible encodings have a known maximum size, then the [`SizedEncode`](crate::SizedEncode) trait should additionally be implemented. /// If all possible encodings have a known maximum size, then the [`SizedEncode`](crate::encode::SizedEncode) trait should additionally be implemented.
/// ///
/// # Examples /// # Examples
/// ///
@ -107,7 +107,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
/// // plementation is equivalent to what would have /// // plementation is equivalent to what would have
/// // been derived. /// // been derived.
/// ///
/// use librum::{Encode, OStream}; /// use oct::encode::{Encode, Output};
/// use core::convert::Infallible; /// use core::convert::Infallible;
/// ///
/// struct Foo { /// struct Foo {
@ -120,13 +120,13 @@ use std::time::{SystemTime, UNIX_EPOCH};
/// ///
/// type Error = Infallible; /// type Error = Infallible;
/// ///
/// fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { /// fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
/// // Encode fields using chaining. /// // Encode fields using chaining.
/// ///
/// self.bar.encode(stream)?; /// self.bar.encode(output)?;
/// self.baz.encode(stream)?; /// self.baz.encode(output)?;
/// ///
/// Ok(()) /// Result::Ok(())
/// } /// }
/// } /// }
/// ``` /// ```
@ -134,7 +134,7 @@ pub trait Encode {
/// The type returned in case of error. /// The type returned in case of error.
type Error; type Error;
/// Encodes `self` into the provided stream. /// Encodes `self` into the provided output.
/// ///
/// # Errors /// # Errors
/// ///
@ -142,16 +142,16 @@ pub trait Encode {
/// ///
/// # Panics /// # Panics
/// ///
/// If `stream` cannot contain the entirety of the resulting encoding, then this method should panic. /// If `output` cannot contain the entirety of the resulting encoding, then this method should panic.
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error>; fn encode(&self, output: &mut Output) -> Result<(), Self::Error>;
} }
impl<T: Encode + ?Sized> Encode for &T { impl<T: Encode + ?Sized> Encode for &T {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, stream) T::encode(self, output)
} }
} }
@ -159,8 +159,8 @@ impl<T: Encode + ?Sized> Encode for &mut T {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, stream) T::encode(self, output)
} }
} }
@ -170,8 +170,8 @@ impl<T: Encode> Encode for (T, ) {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.0.encode(stream) self.0.encode(output)
} }
} }
@ -179,16 +179,17 @@ impl<T: Encode, const N: usize> Encode for [T; N] {
type Error = CollectionEncodeError<Infallible, ItemEncodeError<usize, T::Error>>; type Error = CollectionEncodeError<Infallible, ItemEncodeError<usize, T::Error>>;
/// Encodes each element sequentially. /// Encodes each element sequentially.
/// The length is hard-coded into the type and is therefore not encoded. ///
/// The length `N ` is hard-coded into the type and is therefore not encoded.
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
for (i, v) in self.iter().enumerate() { for (i, v) in self.iter().enumerate() {
v v
.encode(stream) .encode(output)
.map_err(|e| CollectionEncodeError::Item(ItemEncodeError { index: i, error: e }))?; .map_err(|e| CollectionEncodeError::BadItem(ItemEncodeError { index: i, error: e }))?;
} }
Ok(()) Result::Ok(())
} }
} }
@ -197,19 +198,19 @@ impl<T: Encode> Encode for [T] {
/// Encodes each element sequentially with an extra length specifier (of type [`usize`]) prepended first. /// Encodes each element sequentially with an extra length specifier (of type [`usize`]) prepended first.
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self self
.len() .len()
.encode(stream) .encode(output)
.map_err(CollectionEncodeError::Length)?; .map_err(CollectionEncodeError::BadLength)?;
for (i,v) in self.iter().enumerate() { for (i,v) in self.iter().enumerate() {
v v
.encode(stream) .encode(output)
.map_err(|e| CollectionEncodeError::Item(ItemEncodeError { index: i, error: e }))?; .map_err(|e| CollectionEncodeError::BadItem(ItemEncodeError { index: i, error: e }))?;
} }
Ok(()) Result::Ok(())
} }
} }
@ -219,17 +220,18 @@ impl<T: Encode + ?Sized> Encode for Arc<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, stream) T::encode(self, output)
} }
} }
impl Encode for bool { impl Encode for bool {
type Error = <u8 as Encode>::Error; type Error = <u8 as Encode>::Error;
/// Encodes the raw representationf of the boolean.
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
u8::from(*self).encode(stream) u8::from(*self).encode(output)
} }
} }
@ -237,24 +239,24 @@ impl<T: Encode> Encode for Bound<T> {
type Error = EnumEncodeError<u8, T::Error>; type Error = EnumEncodeError<u8, T::Error>;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
match *self { match *self {
Self::Included(ref bound) => { Self::Included(ref bound) => {
0x0u8.encode(stream).unwrap(); let Ok(_) = 0x0u8.encode(output);
bound.encode(stream).map_err(EnumEncodeError::Field)?; bound.encode(output).map_err(EnumEncodeError::BadField)?;
} }
Self::Excluded(ref bound) => { Self::Excluded(ref bound) => {
0x1u8.encode(stream).unwrap(); let Ok(_) = 0x1u8.encode(output);
bound.encode(stream).map_err(EnumEncodeError::Field)?; bound.encode(output).map_err(EnumEncodeError::BadField)?;
} }
Self::Unbounded => { Self::Unbounded => {
0x2u8.encode(stream).unwrap(); let Ok(_) = 0x2u8.encode(output);
} }
} }
Ok(()) Result::Ok(())
} }
} }
@ -264,8 +266,8 @@ impl<T: Encode + ?Sized> Encode for Box<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, stream) T::encode(self, output)
} }
} }
@ -273,8 +275,8 @@ impl<T: Copy + Encode> Encode for Cell<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.get().encode(stream) self.get().encode(output)
} }
} }
@ -282,8 +284,8 @@ impl Encode for char {
type Error = <u32 as Encode>::Error; type Error = <u32 as Encode>::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
u32::from(*self).encode(stream) u32::from(*self).encode(output)
} }
} }
@ -293,8 +295,8 @@ impl<T: Encode + ?Sized + ToOwned> Encode for Cow<'_, T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, stream) T::encode(self, output)
} }
} }
@ -303,8 +305,8 @@ impl Encode for CStr {
/// Encodes the string identically to [a byte slice](slice) containing the string's byte values **excluding** the null terminator. /// Encodes the string identically to [a byte slice](slice) containing the string's byte values **excluding** the null terminator.
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.to_bytes().encode(stream) self.to_bytes().encode(output)
} }
} }
@ -315,8 +317,8 @@ impl Encode for CString {
/// See the the implementation of [`CStr`]. /// See the the implementation of [`CStr`].
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_c_str().encode(stream) self.as_c_str().encode(output)
} }
} }
@ -325,11 +327,11 @@ impl Encode for Duration {
/// Encodes the duration's seconds and nanoseconds counters sequentially. /// Encodes the duration's seconds and nanoseconds counters sequentially.
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_secs().encode(stream).unwrap(); self.as_secs().encode(output)?;
self.subsec_nanos().encode(stream).unwrap(); self.subsec_nanos().encode(output)?;
Ok(()) Result::Ok(())
} }
} }
@ -344,13 +346,13 @@ where
type Error = E; type Error = E;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
for (key, value) in self { for (key, value) in self {
key.encode(stream)?; key.encode(output)?;
value.encode(stream)?; value.encode(output)?;
} }
Ok(()) Result::Ok(())
} }
} }
@ -364,12 +366,12 @@ where
type Error = K::Error; type Error = K::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
for key in self { for key in self {
key.encode(stream)?; key.encode(output)?;
} }
Ok(()) Result::Ok(())
} }
} }
@ -379,9 +381,9 @@ impl Encode for Infallible {
type Error = Self; type Error = Self;
#[inline(always)] #[inline(always)]
fn encode(&self, _stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, _output: &mut Output) -> Result<(), Self::Error> {
// SAFETY: `Infallible` can **never** be construct- // SAFETY: `Infallible` objects can never be con-
// ed. // structed
unsafe { unreachable_unchecked() } unsafe { unreachable_unchecked() }
} }
} }
@ -393,22 +395,22 @@ impl Encode for IpAddr {
/// ///
/// See also the implementations of [`Ipv4Addr`] and [`Ipv6Addr`]. /// See also the implementations of [`Ipv4Addr`] and [`Ipv6Addr`].
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
// The discriminant here is the IP version. // The discriminant here is the IP version.
match *self { match *self {
Self::V4(ref addr) => { Self::V4(ref addr) => {
0x4u8.encode(stream).map_err(EnumEncodeError::Discriminant)?; 0x4u8.encode(output).map_err(EnumEncodeError::BadDiscriminant)?;
addr.encode(stream).map_err(EnumEncodeError::Field)?; addr.encode(output).map_err(EnumEncodeError::BadField)?;
} }
Self::V6(ref addr) => { Self::V6(ref addr) => {
0x6u8.encode(stream).map_err(EnumEncodeError::Discriminant)?; 0x6u8.encode(output).map_err(EnumEncodeError::BadDiscriminant)?;
addr.encode(stream).map_err(EnumEncodeError::Field)?; addr.encode(output).map_err(EnumEncodeError::BadField)?;
} }
} }
Ok(()) Result::Ok(())
} }
} }
@ -417,9 +419,9 @@ impl Encode for Ipv4Addr {
/// Encodes the address's bits in big-endian. /// Encodes the address's bits in big-endian.
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
let value = self.to_bits(); let value = self.to_bits();
value.encode(stream) value.encode(output)
} }
} }
@ -428,9 +430,9 @@ impl Encode for Ipv6Addr {
/// Encodes the address's bits in big-endian. /// Encodes the address's bits in big-endian.
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
let value = self.to_bits(); let value = self.to_bits();
value.encode(stream) value.encode(output)
} }
} }
@ -439,12 +441,12 @@ impl Encode for isize {
/// Casts `self` to [`i16`] and encodes the result. /// Casts `self` to [`i16`] and encodes the result.
#[inline] #[inline]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
let value = i16::try_from(*self) let value = i16::try_from(*self)
.map_err(|_| IsizeEncodeError(*self))?; .map_err(|_| IsizeEncodeError(*self))?;
value.encode(stream).unwrap(); let Ok(_) = value.encode(output);
Ok(()) Result::Ok(())
} }
} }
@ -452,8 +454,8 @@ impl<T: Encode> Encode for LazyCell<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, stream) T::encode(self, output)
} }
} }
@ -463,8 +465,8 @@ impl<T: Encode> Encode for LazyLock<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, stream) T::encode(self, output)
} }
} }
@ -474,19 +476,19 @@ impl<T: Encode<Error = E>, E> Encode for LinkedList<T> {
type Error = CollectionEncodeError<UsizeEncodeError, (usize, E)>; type Error = CollectionEncodeError<UsizeEncodeError, (usize, E)>;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self self
.len() .len()
.encode(stream) .encode(output)
.map_err(CollectionEncodeError::Length)?; .map_err(CollectionEncodeError::BadLength)?;
for (i, v) in self.iter().enumerate() { for (i, v) in self.iter().enumerate() {
v v
.encode(stream) .encode(output)
.map_err(|e| CollectionEncodeError::Item((i, e)))?; .map_err(|e| CollectionEncodeError::BadItem((i, e)))?;
} }
Ok(()) Result::Ok(())
} }
} }
@ -496,11 +498,11 @@ impl<T: Encode + ?Sized> Encode for Mutex<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self self
.lock() .lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) .unwrap_or_else(std::sync::PoisonError::into_inner)
.encode(stream) .encode(output)
} }
} }
@ -511,19 +513,24 @@ impl<T: Encode> Encode for Option<T> {
/// This is `false` for `None` instances and `true` for `Some` instances. /// This is `false` for `None` instances and `true` for `Some` instances.
/// ///
/// If `Some`, then the contained value is encoded after this sign.. /// If `Some`, then the contained value is encoded after this sign..
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
match *self { match *self {
None => { None => {
false.encode(stream).unwrap(); false
.encode(output)
.map_err::<Self::Error, _>(|_v| unreachable!())?;
} }
Some(ref v) => { Some(ref v) => {
true.encode(stream).unwrap(); true
v.encode(stream)?; .encode(output)
.map_err::<Self::Error, _>(|_v| unreachable!())?;
v.encode(output)?;
} }
}; };
Ok(()) Result::Ok(())
} }
} }
@ -531,8 +538,8 @@ impl<T> Encode for PhantomData<T> {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn encode(&self, _stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, _output: &mut Output) -> Result<(), Self::Error> {
Ok(()) Result::Ok(())
} }
} }
@ -540,8 +547,8 @@ impl Encode for PhantomPinned {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn encode(&self, _stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, _output: &mut Output) -> Result<(), Self::Error> {
Ok(()) Result::Ok(())
} }
} }
@ -549,11 +556,11 @@ impl<T: Encode> Encode for Range<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.start.encode(stream)?; self.start.encode(output)?;
self.end.encode(stream)?; self.end.encode(output)?;
Ok(()) Result::Ok(())
} }
} }
@ -561,8 +568,8 @@ impl<T: Encode> Encode for RangeFrom<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.start.encode(stream) self.start.encode(output)
} }
} }
@ -570,8 +577,8 @@ impl Encode for RangeFull {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn encode(&self, _stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, _output: &mut Output) -> Result<(), Self::Error> {
Ok(()) Result::Ok(())
} }
} }
@ -579,11 +586,11 @@ impl<T: Encode> Encode for RangeInclusive<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.start().encode(stream)?; self.start().encode(output)?;
self.end().encode(stream)?; self.end().encode(output)?;
Ok(()) Result::Ok(())
} }
} }
@ -591,8 +598,8 @@ impl<T: Encode> Encode for RangeTo<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.end.encode(stream) self.end.encode(output)
} }
} }
@ -600,10 +607,10 @@ impl<T: Encode> Encode for RangeToInclusive<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.end.encode(stream)?; self.end.encode(output)?;
Ok(()) Result::Ok(())
} }
} }
@ -613,8 +620,8 @@ impl<T: Encode + ?Sized> Encode for Rc<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, stream) T::encode(self, output)
} }
} }
@ -622,21 +629,22 @@ impl<T: Encode + ?Sized> Encode for RefCell<T> {
type Error = RefCellEncodeError<T::Error>; type Error = RefCellEncodeError<T::Error>;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
let value = self.try_borrow() let value = self
.map_err(RefCellEncodeError::Borrow)?; .try_borrow()
.map_err(RefCellEncodeError::BadBorrow)?;
T::encode(&value, stream) T::encode(&value, output)
.map_err(RefCellEncodeError::Value)?; .map_err(RefCellEncodeError::BadValue)?;
Ok(()) Result::Ok(())
} }
} }
impl<T, E, Err> Encode for core::result::Result<T, E> impl<T, E, Err> Encode for Result<T, E>
where where
T: Encode<Error = Err>, T: Encode<Error = Err>,
E: Encode<Error = Err>, E: Encode<Error: Into<Err>>,
{ {
type Error = Err; type Error = Err;
@ -645,23 +653,25 @@ where
/// ///
/// If `Ok`, then the contained value is encoded after this sign. /// If `Ok`, then the contained value is encoded after this sign.
#[inline] #[inline]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
// The sign here is `false` for `Ok` objects and // The sign here is `false` for `Ok` objects and
// `true` for `Err` objects. // `true` for `Err` objects.
match *self { match *self {
Ok(ref v) => { Ok(ref v) => {
false.encode(stream).unwrap(); let Ok(_) = false.encode(output);
v.encode(stream)?;
v.encode(output)?;
} }
Err(ref e) => { Err(ref e) => {
true.encode(stream).unwrap(); let Ok(_) = true.encode(output);
e.encode(stream)?;
e.encode(output).map_err(Into::into)?;
} }
}; };
Ok(()) Result::Ok(())
} }
} }
@ -671,11 +681,11 @@ impl<T: Encode + ?Sized> Encode for RwLock<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self self
.read() .read()
.or_else(|e| Ok(e.into_inner()))? .or_else(|e| Ok(e.into_inner()))?
.encode(stream) .encode(output)
} }
} }
@ -683,8 +693,8 @@ impl<T: Encode> Encode for Saturating<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.0.encode(stream) self.0.encode(output)
} }
} }
@ -694,22 +704,22 @@ impl Encode for SocketAddr {
/// This implementation encoded as discriminant denoting the IP version of the address (i.e. `4` for IPv4 and `6` for IPv6). /// This implementation encoded as discriminant denoting the IP version of the address (i.e. `4` for IPv4 and `6` for IPv6).
/// This is then followed by the respective address' own encoding (either [`SocketAddrV4`] or [`SocketAddrV6`]). /// This is then followed by the respective address' own encoding (either [`SocketAddrV4`] or [`SocketAddrV6`]).
#[inline] #[inline]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
// The discriminant here is the IP version. // The discriminant here is the IP version.
match *self { match *self {
Self::V4(ref addr) => { Self::V4(ref addr) => {
0x4u8.encode(stream)?; 0x4u8.encode(output)?;
addr.encode(stream)?; addr.encode(output)?;
} }
Self::V6(ref addr) => { Self::V6(ref addr) => {
0x6u8.encode(stream)?; 0x6u8.encode(output)?;
addr.encode(stream)?; addr.encode(output)?;
} }
} }
Ok(()) Result::Ok(())
} }
} }
@ -718,11 +728,11 @@ impl Encode for SocketAddrV4 {
/// Encodes the address's bits followed by the port number, both of which in big-endian. /// Encodes the address's bits followed by the port number, both of which in big-endian.
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.ip().encode(stream)?; self.ip().encode(output)?;
self.port().encode(stream)?; self.port().encode(output)?;
Ok(()) Result::Ok(())
} }
} }
@ -731,13 +741,13 @@ impl Encode for SocketAddrV6 {
/// Encodes the address's bits followed by the port number, flow information, and scope identifier -- all of which in big-endian. /// Encodes the address's bits followed by the port number, flow information, and scope identifier -- all of which in big-endian.
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.ip().encode(stream)?; self.ip().encode(output)?;
self.port().encode(stream)?; self.port().encode(output)?;
self.flowinfo().encode(stream)?; self.flowinfo().encode(output)?;
self.scope_id().encode(stream)?; self.scope_id().encode(output)?;
Ok(()) Result::Ok(())
} }
} }
@ -746,8 +756,8 @@ impl Encode for str {
/// Encodes the string identically to [a byte slice](slice) containing the string's byte values. /// Encodes the string identically to [a byte slice](slice) containing the string's byte values.
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_bytes().encode(stream) self.as_bytes().encode(output)
} }
} }
@ -758,8 +768,8 @@ impl Encode for String {
/// See [`str`]. /// See [`str`].
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_str().encode(stream) self.as_str().encode(output)
} }
} }
@ -772,7 +782,7 @@ impl Encode for SystemTime {
/// ///
/// Examples of some timestamps and their encodings include: /// Examples of some timestamps and their encodings include:
/// ///
/// | ISO 8601 | UNIX / Librum | /// | ISO 8601 | UNIX / oct |
/// | :-------------------------- | -------------: | /// | :-------------------------- | -------------: |
/// | `2024-11-03T12:02:01+01:00` | +1730631721 | /// | `2024-11-03T12:02:01+01:00` | +1730631721 |
/// | `1989-06-03T20:00:00+09:00` | +13258800 | /// | `1989-06-03T20:00:00+09:00` | +13258800 |
@ -780,7 +790,7 @@ impl Encode for SystemTime {
/// | `1945-05-04T18:30:00+02:00` | -778231800 | /// | `1945-05-04T18:30:00+02:00` | -778231800 |
#[expect(clippy::cast_possible_wrap)] #[expect(clippy::cast_possible_wrap)]
#[inline] #[inline]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
let time = if *self >= UNIX_EPOCH { let time = if *self >= UNIX_EPOCH {
let duration = self let duration = self
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
@ -795,8 +805,8 @@ impl Encode for SystemTime {
0x0 - duration.as_secs() as i64 0x0 - duration.as_secs() as i64
}; };
time.encode(stream).unwrap(); time.encode(output)?;
Ok(()) Result::Ok(())
} }
} }
@ -804,8 +814,8 @@ impl Encode for () {
type Error = Infallible; type Error = Infallible;
#[inline(always)] #[inline(always)]
fn encode(&self, _stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, _output: &mut Output) -> Result<(), Self::Error> {
Ok(()) Result::Ok(())
} }
} }
@ -814,12 +824,12 @@ impl Encode for usize {
/// Casts `self` to [`u16`] and encodes the result. /// Casts `self` to [`u16`] and encodes the result.
#[inline] #[inline]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
let value = u16::try_from(*self) let value = u16::try_from(*self)
.map_err(|_| UsizeEncodeError(*self))?; .map_err(|_e| UsizeEncodeError(*self))?;
value.encode(stream).unwrap(); let Ok(_) = value.encode(output);
Ok(()) Result::Ok(())
} }
} }
@ -829,8 +839,8 @@ impl<T: Encode> Encode for Vec<T> {
type Error = <[T] as Encode>::Error; type Error = <[T] as Encode>::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_slice().encode(stream) self.as_slice().encode(output)
} }
} }
@ -838,21 +848,21 @@ impl<T: Encode> Encode for Wrapping<T> {
type Error = T::Error; type Error = T::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.0.encode(stream) self.0.encode(output)
} }
} }
macro_rules! impl_numeric { macro_rules! impl_numeric {
($ty:ty$(,)?) => { ($ty:ty$(,)?) => {
impl ::librum::Encode for $ty { impl ::oct::encode::Encode for $ty {
type Error = ::core::convert::Infallible; type Error = ::core::convert::Infallible;
#[inline] #[inline]
fn encode(&self, stream: &mut OStream) -> ::core::result::Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> ::core::result::Result<(), Self::Error> {
stream.write(&self.to_le_bytes()); output.write(&self.to_le_bytes()).unwrap();
Ok(()) Result::Ok(())
} }
} }
}; };
@ -863,20 +873,20 @@ macro_rules! impl_tuple {
$($captures:ident: $tys:ident),+$(,)? $($captures:ident: $tys:ident),+$(,)?
} => { } => {
#[doc(hidden)] #[doc(hidden)]
impl<$($tys, )* E> ::librum::Encode for ($($tys, )*) impl<$($tys, )* E> ::oct::encode::Encode for ($($tys, )*)
where where
$($tys: Encode<Error = E>, )* { $($tys: Encode<Error = E>, )* {
type Error = E; type Error = E;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut ::librum::OStream) -> ::core::result::Result<(), Self::Error> { fn encode(&self, output: &mut ::oct::encode::Output) -> ::core::result::Result<(), Self::Error> {
let ($(ref $captures, )*) = *self; let ($(ref $captures, )*) = *self;
$( $(
$captures.encode(stream)?; $captures.encode(output)?;
)* )*
Ok(()) Result::Ok(())
} }
} }
}; };
@ -884,12 +894,12 @@ macro_rules! impl_tuple {
macro_rules! impl_non_zero { macro_rules! impl_non_zero {
($ty:ty$(,)?) => { ($ty:ty$(,)?) => {
impl ::librum::Encode for ::core::num::NonZero<$ty> { impl ::oct::encode::Encode for ::core::num::NonZero<$ty> {
type Error = <$ty as ::librum::Encode>::Error; type Error = <$ty as ::oct::encode::Encode>::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> ::core::result::Result<(), Self::Error> { fn encode(&self, output: &mut ::oct::encode::Output) -> ::core::result::Result<(), Self::Error> {
self.get().encode(stream) self.get().encode(output)
} }
} }
}; };
@ -903,15 +913,17 @@ macro_rules! impl_atomic {
} => { } => {
#[cfg(target_has_atomic = $width)] #[cfg(target_has_atomic = $width)]
#[cfg_attr(doc, doc(cfg(target_has_atomic = $width)))] #[cfg_attr(doc, doc(cfg(target_has_atomic = $width)))]
impl ::librum::Encode for $atomic_ty { impl ::oct::encode::Encode for $atomic_ty {
type Error = <$ty as ::librum::Encode>::Error; type Error = <$ty as ::oct::encode::Encode>::Error;
/// Encodes the atomic with the same scheme as that of the atomic type's primitive counterpart. /// Encodes the atomic with the same scheme as that of the atomic type's primitive counterpart.
/// ///
/// The atomic object itself is read with the [`Relaxed`](core::sync::atomic::Ordering) ordering scheme. /// The atomic object itself is read with the [`Relaxed`](core::sync::atomic::Ordering) ordering scheme.
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut ::librum::OStream) -> ::core::result::Result<(), Self::Error> { fn encode(&self, output: &mut ::oct::encode::Output) -> ::core::result::Result<(), Self::Error> {
self.load(::std::sync::atomic::Ordering::Relaxed).encode(stream) use ::std::sync::atomic::Ordering;
self.load(Ordering::Relaxed).encode(output)
} }
} }
}; };

View file

@ -1,6 +1,6 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of librum. // This file is part of oct.
//test!(you can redistribut => []); //test!(you can redistribut => []);
// it and/or modify it under the terms of the GNU // it and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
@ -8,17 +8,18 @@
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use librum::{Encode, OStream, SizedEncode, SizedStr}; use oct::SizedStr;
use oct::encode::{Encode, Output, SizedEncode};
use std::time::Duration; use std::time::Duration;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use std::vec; use std::vec;
@ -30,10 +31,10 @@ macro_rules! test {
let mut buf = vec![0x00; data.len()]; let mut buf = vec![0x00; data.len()];
let mut stream = OStream::new(&mut buf); let mut stream = Output::new(&mut buf);
<$ty as Encode>::encode(&$value, &mut stream).unwrap(); <$ty as Encode>::encode(&$value, &mut stream).unwrap();
let len = stream.close(); let len = stream.position();
assert_eq!(&buf[..len], data.as_slice()); assert_eq!(&buf[..len], data.as_slice());
}}; }};
} }
@ -68,7 +69,7 @@ fn test_encode() {
0xB1, 0x03, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00,
]); ]);
test!(Result::<u16, char>: Ok(0x45_45) => [0x00, 0x45, 0x45]); test!(Result::<u16, char>: Ok(0x4545) => [0x00, 0x45, 0x45]);
test!(Result::<u16, char>: Err(char::REPLACEMENT_CHARACTER) => [0x01, 0xFD, 0xFF, 0x00, 0x00]); test!(Result::<u16, char>: Err(char::REPLACEMENT_CHARACTER) => [0x01, 0xFD, 0xFF, 0x00, 0x00]);

134
oct/src/encode/mod.rs Normal file
View file

@ -0,0 +1,134 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
// This file is part of oct.
//
// oct 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.
//
// oct 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 oct. If
// not, see <https://www.gnu.org/licenses/>.
//! Error variants.
//!
//! This module defines the error types used by oct.
//! All of these types define (at least conditionally) the [`Error`](core::error::Error) trait.
use crate::use_mod;
use_mod!(pub encode);
use_mod!(pub output);
use_mod!(pub sized_encode);
/// Implements [`Encode`] for the provided type.
///
/// This derive macro assumes that all fields implement <code>Encode&lt;[Error]: [Into]&lt;[GenericEncodeError]&gt;&gt;</code>.
/// If this is **not** the case, then the trait should be implemented manually instead.
///
/// [Error]: Encode::Error
/// [GenericEncodeError]: crate::error::GenericEncodeError
///
/// Do also consider deriving [`SizedEncode`](derive@SizedEncode) -- if possible.
///
/// # Structs
///
/// For structures, each element is chained in **order of declaration.**
/// If the structure is a unit structure (i.e. it has *no* fields) then it is encoded equivalently to the [unit] type.
///
/// For example, the following struct will encode its field `foo` followed by `bar`:
///
/// ```
/// use oct::encode::Encode;
///
/// #[derive(Encode)]
/// struct FooBar {
/// pub foo: char,
/// pub bar: char,
/// }
/// ```
///
/// This should be kept in mind when changing the structure's declarationm as doing so may invalidate previous encodings.
///
/// The [`Error`](Encode::Error) type will in all cases just be `GenericEncodeError`.
///
/// # Enums
///
/// Enumerations encode like structures except that each variant additionally encodes a unique discriminant.
///
/// By default, each discriminant is assigned from the range 0 to infinite, to the extend allowed by the [`isize`] type and its encoding (as which **all** discriminants are encoded).
/// A custom discriminant may be set instead by assigning the variant an integer constant.
/// Unspecified discriminants then increment the previous variant's discriminant:
///
/// ```
/// use oct::Slot;
/// use oct::encode::Encode;
///
/// #[derive(Encode)]
/// enum Num {
/// Two = 0x2,
///
/// Three,
///
/// Zero = 0x0,
///
/// One,
/// }
///
/// let mut buf = Slot::with_capacity(size_of::<i16>());
///
/// buf.write(Num::Zero).unwrap();
/// assert_eq!(buf, [0x00, 0x00].as_slice());
///
/// buf.write(Num::One).unwrap();
/// assert_eq!(buf, [0x01, 0x00].as_slice());
///
/// buf.write(Num::Two).unwrap();
/// assert_eq!(buf, [0x02, 0x00].as_slice());
///
/// buf.write(Num::Three).unwrap();
/// assert_eq!(buf, [0x03, 0x00].as_slice());
/// ```
///
/// Variants with fields are encoded exactly like structures.
/// That is, each field is chained in order of declaration.
///
/// For error handling, the `Error` type is defined as:
///
/// <code>[EnumEncodeError]&lt;&lt;Repr as Encode&gt;::Error, GenericEncodeError&gt;</code>,
///
/// [EnumEncodeError]: crate::error::GenericEncodeError
///
/// wherein `Repr` is the enumeration's representation.
///
/// # Unions
///
/// Unions cannot derive `Encode` due to the uncertainty of their contents.
/// The trait should therefore be implemented manually for such types.
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc, doc(cfg(feature = "proc-macro")))]
#[doc(inline)]
pub use oct_macros::Encode;
/// Implements [`Encode`](trait@Encode) using the default implementation.
///
/// For simple structures, the value of [`MAX_ENCODED_SIZE`](SizedEncode::MAX_ENCODED_SIZE) is set as the combined value of <code>T*n*::MAX_ENCODED_SIZE</code> wherein <code>T*n*</code> is the type of each field.
///
/// For enumerations, the value is set such that each variant is treated like a structure (with the discriminant as an extra field) and where the variant that produces the largest `MAX_ENCODED_SIZE` is chosen.
///
/// As untagged unions cannot derive `Encode`, `SizedEncode` also cannot be derived for them.
///
/// Do remember that deriving this trait is only recommended
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc, doc(cfg(feature = "proc-macro")))]
#[doc(inline)]
pub use oct_macros::SizedEncode;

View file

@ -0,0 +1,156 @@
// 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 <https://www.gnu.org/licenses/>.
use crate::error::OutputError;
use core::borrow::Borrow;
use core::ptr::copy_nonoverlapping;
use core::slice;
/// Byte stream suitable for writing.
#[derive(Eq)]
pub struct Output<'a> {
buf: &'a mut [u8],
pos: usize,
}
impl<'a> Output<'a> {
/// Constructs a new o-stream.
#[inline(always)]
#[must_use]
pub const fn new(buf: &'a mut [u8]) -> Self {
Self { buf, pos: 0x0 }
}
/// Writes bytes to the stream.
///
/// # Panics
///
/// If the requested amount of bytes could not exactly be written, then this method will panic.
#[inline]
pub const fn write(&mut self, data: &[u8]) -> Result<(), OutputError> {
let remaining = self.buf.len() - self.pos;
let count = data.len();
if remaining < count {
return Err(OutputError {
capacity: self.buf.len(),
position: self.pos,
count,
});
}
unsafe {
let src = data.as_ptr();
let dst = self.buf.as_mut_ptr().add(self.pos);
copy_nonoverlapping(src, dst, count);
}
self.pos += count;
Ok(())
}
/// Gets a pointer to the first byte of the output stream.
#[inline(always)]
#[must_use]
pub const fn as_ptr(&self) -> *const u8 {
self.buf.as_ptr()
}
/// Gets a slice of the written bytes in the output stream.
#[inline(always)]
#[must_use]
pub const fn as_slice(&self) -> &[u8] {
unsafe {
let ptr = self.as_ptr();
let len = self.position();
slice::from_raw_parts(ptr, len)
}
}
/// Retrieves the maximum capacity of the output stream.
#[inline(always)]
#[must_use]
pub const fn capacity(&self) -> usize {
self.buf.len()
}
/// Retrieves the remaining, free capacity of the output stream.
#[inline(always)]
#[must_use]
pub const fn remaining(&self) -> usize {
// SAFETY: The cursor position can never exceed the
// stream's capacity.
unsafe { self.capacity().unchecked_sub(self.position()) }
}
/// Retrieves the current cursor position of the output stream.
#[inline(always)]
#[must_use]
pub const fn position(&self) -> usize {
self.pos
}
}
impl AsRef<[u8]> for Output<'_> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl Borrow<[u8]> for Output<'_> {
#[inline(always)]
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}
impl PartialEq for Output<'_> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl PartialEq<[u8]> for Output<'_> {
#[inline(always)]
fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other
}
}
impl PartialEq<&[u8]> for Output<'_> {
#[inline(always)]
fn eq(&self, other: &&[u8]) -> bool {
self.as_slice() == *other
}
}
impl PartialEq<&mut [u8]> for Output<'_> {
#[inline(always)]
fn eq(&self, other: &&mut [u8]) -> bool {
self.as_slice() == *other
}
}

View file

@ -1,28 +1,28 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::Encode; use crate::encode::Encode;
use core::cell::{Cell, LazyCell, RefCell}; use core::cell::{Cell, LazyCell, RefCell};
use core::convert::Infallible; use core::convert::Infallible;
@ -74,7 +74,7 @@ use std::time::SystemTime;
/// The general rule is that the size limit must be a substantial part of a type's design to constitute implementing this trait. /// The general rule is that the size limit must be a substantial part of a type's design to constitute implementing this trait.
/// ///
/// Also note that -- in practice -- this trait is **not** strictly enforceable. /// Also note that -- in practice -- this trait is **not** strictly enforceable.
/// Users of the `Encode` and [`Decode`](crate::Decode) traits should assume that this trait is mostly properly defined, but should also still leave room for the possibility that it isn't. /// Users of the `Encode` and [`Decode`](crate::decode::Decode) traits should assume that this trait is mostly properly defined, but should also still leave room for the possibility that it isn't.
pub trait SizedEncode: Encode + Sized { pub trait SizedEncode: Encode + Sized {
/// The maximum guaranteed amount of bytes that can result from an encoding. /// The maximum guaranteed amount of bytes that can result from an encoding.
/// ///
@ -278,7 +278,7 @@ impl<T: SizedEncode> SizedEncode for Wrapping<T> {
macro_rules! impl_numeric { macro_rules! impl_numeric {
($ty:ty$(,)?) => { ($ty:ty$(,)?) => {
impl ::librum::SizedEncode for $ty { impl ::oct::encode::SizedEncode for $ty {
const MAX_ENCODED_SIZE: usize = size_of::<$ty>(); const MAX_ENCODED_SIZE: usize = size_of::<$ty>();
} }
}; };
@ -289,18 +289,18 @@ macro_rules! impl_tuple {
$($tys:ident),+$(,)? $($tys:ident),+$(,)?
} => { } => {
#[doc(hidden)] #[doc(hidden)]
impl<$($tys, )* E> ::librum::SizedEncode for ($($tys, )*) impl<$($tys, )* E> ::oct::encode::SizedEncode for ($($tys, )*)
where where
$($tys: SizedEncode + Encode<Error = E>, )* { $($tys: SizedEncode + Encode<Error = E>, )* {
const MAX_ENCODED_SIZE: usize = 0x0 $(+ <$tys as ::librum::SizedEncode>::MAX_ENCODED_SIZE)*; const MAX_ENCODED_SIZE: usize = 0x0 $(+ <$tys as ::oct::encode::SizedEncode>::MAX_ENCODED_SIZE)*;
} }
}; };
} }
macro_rules! impl_non_zero { macro_rules! impl_non_zero {
($ty:ty$(,)?) => { ($ty:ty$(,)?) => {
impl ::librum::SizedEncode for ::core::num::NonZero<$ty> { impl ::oct::encode::SizedEncode for ::core::num::NonZero<$ty> {
const MAX_ENCODED_SIZE: usize = <$ty as ::librum::SizedEncode>::MAX_ENCODED_SIZE; const MAX_ENCODED_SIZE: usize = <$ty as ::oct::encode::SizedEncode>::MAX_ENCODED_SIZE;
} }
}; };
} }
@ -313,8 +313,8 @@ macro_rules! impl_atomic {
} => { } => {
#[cfg(target_has_atomic = $width)] #[cfg(target_has_atomic = $width)]
#[cfg_attr(doc, doc(cfg(target_has_atomic = $width)))] #[cfg_attr(doc, doc(cfg(target_has_atomic = $width)))]
impl ::librum::SizedEncode for $atomic_ty { impl ::oct::encode::SizedEncode for $atomic_ty {
const MAX_ENCODED_SIZE: usize = <$ty as ::librum::SizedEncode>::MAX_ENCODED_SIZE; const MAX_ENCODED_SIZE: usize = <$ty as ::oct::encode::SizedEncode>::MAX_ENCODED_SIZE;
} }
}; };
} }

View file

@ -1,25 +1,26 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use librum::{Encode, SizedStr, SizedEncode}; use oct::SizedStr;
use oct::encode::{Encode, SizedEncode};
use std::convert::Infallible; use std::convert::Infallible;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::net::{ use std::net::{
@ -34,7 +35,7 @@ use std::num::NonZero;
macro_rules! assert_encoded_size { macro_rules! assert_encoded_size {
($ty:ty, $value:expr$(,)?) => {{ ($ty:ty, $value:expr$(,)?) => {{
assert_eq!(<$ty as ::librum::SizedEncode>::MAX_ENCODED_SIZE, $value); assert_eq!(<$ty as ::oct::encode::SizedEncode>::MAX_ENCODED_SIZE, $value);
}}; }};
} }

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::error::Error; use core::error::Error;
@ -24,7 +24,7 @@ use core::fmt::{self, Display, Formatter};
/// A C-like string could not be decoded. /// A C-like string could not be decoded.
/// ///
/// This error is generatead when <code>&lt;[CString](alloc::ffi::CString) as [Decode](crate::Decode)&gt;::[decode](crate::Decode::decode)</code> encounteres a null byte within bounds. /// This error is generatead when <code>&lt;[CString](alloc::ffi::CString) as [Decode](crate::decode::Decode)&gt;::[decode](crate::decode::Decode::decode)</code> encounteres a null byte within bounds.
/// ///
/// Note that although any null value is *theoretically* also the string's null terminator, the implementations for [`CStr`](core::ffi::CStr) and `CString` use the same encoding scheme as [`[u8]`](slice). /// Note that although any null value is *theoretically* also the string's null terminator, the implementations for [`CStr`](core::ffi::CStr) and `CString` use the same encoding scheme as [`[u8]`](slice).
/// This is mainly for efficiency's sake (as to allow the entire stream to be read at once), but this also allows for the aforementioned case to happen. /// This is mainly for efficiency's sake (as to allow the entire stream to be read at once), but this also allows for the aforementioned case to happen.

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::error::Error; use core::error::Error;
@ -28,7 +28,7 @@ use core::fmt::{self, Display, Formatter};
/// UTF-32 (the format used by the [`char`] data type) additionally specifies that these code points are padded to 32 bits. /// UTF-32 (the format used by the [`char`] data type) additionally specifies that these code points are padded to 32 bits.
/// ///
/// The encoding scheme used by `char` yields an untransformed representation (disregarding endian corrections), but this regrettably also leads to many bit patterns being undefined with respect to UTF-32. /// The encoding scheme used by `char` yields an untransformed representation (disregarding endian corrections), but this regrettably also leads to many bit patterns being undefined with respect to UTF-32.
/// If any of these values is read by <code>&lt;char as [Decode](crate::Decode)&gt;::[decode](crate::Decode::decode)</code>, then an instance of this error type is returned. /// If any of these values is read by <code>&lt;char as [Decode](crate::decode::Decode)&gt;::[decode](crate::decode::Decode::decode)</code>, then an instance of this error type is returned.
#[derive(Debug)] #[derive(Debug)]
#[must_use] #[must_use]
pub struct CharDecodeError { pub struct CharDecodeError {

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::convert::Infallible; use core::convert::Infallible;
@ -26,11 +26,11 @@ use core::fmt::{self, Display, Formatter};
/// A collection could not be decoded. /// A collection could not be decoded.
/// ///
/// This type is intended as a partially-generic decode error for collections. /// This type is intended as a partially-generic decode error for collections.
/// It supports denoting an error for when the collection's length is invalid -- see the [`Length`](Self::Length) variant -- and when an element is invalid -- see the [`Item`](Self::Item)) variant. /// It supports denoting an error for when the collection's length is invalid -- see the [`BadLength`](Self::BadLength) variant -- and when an element is invalid -- see the [`Item`](Self::BadItem)) variant.
/// ///
/// The most common form of this type is <code>CollectionDecodeError<[Infallible](core::convert::Infallible), [ItemDecodeError](crate::error::ItemDecodeError)<[usize], ..></code>, but this may not always necessarily be the preferred form. /// The most common form of this type is <code>CollectionDecodeError<[Infallible](core::convert::Infallible), [ItemDecodeError](crate::error::ItemDecodeError)<[usize], ..></code>, but this may not always necessarily be the preferred form.
/// ///
/// An example of a type using a different form is [`SizedStr`](crate::SizedStr), which uses <code>CollectionDecodeError<[`SizeError`](crate::error::SizeError), [Utf8Error](crate::error::Utf8Error)></code>. /// An example of a type using a different form is [`SizedStr`](crate::SizedStr), which uses <code>CollectionDecodeError<[`LengthError`](crate::error::LengthError), [Utf8Error](crate::error::Utf8Error)></code>.
#[derive(Debug)] #[derive(Debug)]
#[must_use] #[must_use]
pub enum CollectionDecodeError<L, I> { pub enum CollectionDecodeError<L, I> {
@ -39,13 +39,13 @@ pub enum CollectionDecodeError<L, I> {
/// For most dynamically-sized collections, the suitable type here is [`Infallible`] due to there basically being no restriction on the collection's size (depending on the data type used for denoting lengths). /// For most dynamically-sized collections, the suitable type here is [`Infallible`] due to there basically being no restriction on the collection's size (depending on the data type used for denoting lengths).
/// ///
/// Sometimes the length isn't even encoded in the stream (instead lying in the type signature), and in these cases the appropriate type would also be `Infallible`. /// Sometimes the length isn't even encoded in the stream (instead lying in the type signature), and in these cases the appropriate type would also be `Infallible`.
Length(L), BadLength(L),
/// A collection item could not be decoded. /// A collection item could not be decoded.
/// ///
/// Sometimes the index of the item may be desired. /// Sometimes the index of the item may be desired.
/// In these cases the [`ItemDecodeError`](crate::error::ItemDecodeError) could be used here. /// In these cases the [`ItemDecodeError`](crate::error::ItemDecodeError) could be used here.
Item(I), BadItem(I),
} }
impl<L, I> Display for CollectionDecodeError<L, I> impl<L, I> Display for CollectionDecodeError<L, I>
@ -55,13 +55,11 @@ where
{ {
#[inline] #[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use CollectionDecodeError::*;
match *self { match *self {
Length(ref e) Self::BadLength(ref e)
=> write!(f, "unable to decode collection length: {e}"), => write!(f, "unable to decode collection length: {e}"),
Item(ref e) Self::BadItem(ref e)
=> write!(f, "unable to decode collection item: {e}"), => write!(f, "unable to decode collection item: {e}"),
} }
} }
@ -74,12 +72,10 @@ where
{ {
#[inline] #[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
use CollectionDecodeError::*;
match *self { match *self {
Length(ref e) => Some(e), Self::BadLength(ref e) => Some(e),
Item(ref e) => Some(e), Self::BadItem(ref e) => Some(e),
} }
} }
} }

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::convert::Infallible; use core::convert::Infallible;
@ -26,15 +26,15 @@ use core::fmt::{self, Display, Formatter};
/// A collection could not be encoded. /// A collection could not be encoded.
/// ///
/// This type is intended as a partially-generic encode error for collections. /// This type is intended as a partially-generic encode error for collections.
/// It supports denoting an error for when the collection's length is invalid -- see the [`Length`](Self::Length) variant -- and when an element is invalid -- see the [`Item`](Self::Item)) variant. /// It supports denoting an error for when the collection's length is invalid -- see the [`BadLength`](Self::BadLength) variant -- and when an element is invalid -- see the [`Item`](Self::BadItem)) variant.
#[derive(Debug)] #[derive(Debug)]
#[must_use] #[must_use]
pub enum CollectionEncodeError<L, I> { pub enum CollectionEncodeError<L, I> {
/// The collection length could not be encoded. /// The collection length could not be encoded.
Length(L), BadLength(L),
/// A collection item could not be encoded. /// A collection item could not be encoded.
Item(I), BadItem(I),
} }
impl<L, I> Display for CollectionEncodeError<L, I> impl<L, I> Display for CollectionEncodeError<L, I>
@ -44,13 +44,11 @@ where
{ {
#[inline] #[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use CollectionEncodeError::*;
match *self { match *self {
Length(ref e) Self::BadLength(ref e)
=> write!(f, "unable to encode collection length: {e}"), => write!(f, "unable to encode collection length: {e}"),
Item(ref e) Self::BadItem(ref e)
=> write!(f, "unable to encode collection item: {e}"), => write!(f, "unable to encode collection item: {e}"),
} }
} }
@ -63,12 +61,10 @@ where
{ {
#[inline] #[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
use CollectionEncodeError::*;
match *self { match *self {
Length(ref e) => Some(e), Self::BadLength(ref e) => Some(e),
Item(ref e) => Some(e), Self::BadItem(ref e) => Some(e),
} }
} }
} }
@ -83,4 +79,3 @@ where
unreachable!() unreachable!()
} }
} }

View file

@ -1,25 +1,25 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::Decode; use crate::decode::Decode;
use core::convert::Infallible; use core::convert::Infallible;
use core::error::Error; use core::error::Error;
@ -42,7 +42,7 @@ pub enum EnumDecodeError<D: Decode, F> {
}, },
/// A field could not be encoded. /// A field could not be encoded.
Field(F), BadField(F),
} }
impl<D, F> Display for EnumDecodeError<D, F> impl<D, F> Display for EnumDecodeError<D, F>
@ -52,16 +52,14 @@ where
{ {
#[inline] #[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use EnumDecodeError::*;
match *self { match *self {
InvalidDiscriminant(ref e) Self::InvalidDiscriminant(ref e)
=> write!(f, "discriminant could not be decoded: {e}"), => write!(f, "discriminant could not be decoded: {e}"),
UnassignedDiscriminant { ref value } Self::UnassignedDiscriminant { ref value }
=> write!(f, "`{value}` is not an assigned discriminant for the given enumeration"), => write!(f, "`{value}` is not an assigned discriminant for the given enumeration"),
Field(ref e) Self::BadField(ref e)
=> write!(f, "variant could not be decoded: {e}"), => write!(f, "variant could not be decoded: {e}"),
} }
} }
@ -74,12 +72,10 @@ where
{ {
#[inline] #[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
use EnumDecodeError::*;
match *self { match *self {
InvalidDiscriminant(ref e) => Some(e), Self::InvalidDiscriminant(ref e) => Some(e),
Field(ref e) => Some(e), Self::BadField(ref e) => Some(e),
_ => None, _ => None,
} }

View file

@ -1,25 +1,25 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::Encode; use crate::encode::Encode;
use core::convert::Infallible; use core::convert::Infallible;
use core::error::Error; use core::error::Error;
@ -30,10 +30,10 @@ use core::fmt::{self, Debug, Display, Formatter};
#[must_use] #[must_use]
pub enum EnumEncodeError<D: Encode, F> { pub enum EnumEncodeError<D: Encode, F> {
/// The discriminant could not be encoded. /// The discriminant could not be encoded.
Discriminant(D::Error), BadDiscriminant(D::Error),
/// A field could not be encoded. /// A field could not be encoded.
Field(F), BadField(F),
} }
impl<D, F> Display for EnumEncodeError<D, F> impl<D, F> Display for EnumEncodeError<D, F>
@ -43,13 +43,11 @@ where
{ {
#[inline] #[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use EnumEncodeError::*;
match *self { match *self {
Discriminant(ref e) Self::BadDiscriminant(ref e)
=> write!(f, "discriminant could not be encoded: {e}"), => write!(f, "discriminant could not be encoded: {e}"),
Field(ref e) Self::BadField(ref e)
=> write!(f, "field could not be encoded: {e}"), => write!(f, "field could not be encoded: {e}"),
} }
} }
@ -62,12 +60,10 @@ where
{ {
#[inline] #[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
use EnumEncodeError::*;
match *self { match *self {
Discriminant(ref e) => Some(e), Self::BadDiscriminant(ref e) => Some(e),
Field(ref e) => Some(e), Self::BadField(ref e) => Some(e),
} }
} }
} }

View file

@ -1,37 +1,39 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::{Decode, PrimitiveDiscriminant}; use crate::PrimitiveDiscriminant;
use crate::decode::Decode;
use crate::error::{ use crate::error::{
BoolDecodeError,
CollectionDecodeError, CollectionDecodeError,
CStringDecodeError,
EnumDecodeError, EnumDecodeError,
ItemDecodeError, ItemDecodeError,
NonZeroDecodeError, NonZeroDecodeError,
SizeError, LengthError,
Utf8Error, Utf8Error,
SystemTimeDecodeError, SystemTimeDecodeError,
}; };
#[cfg(feature = "alloc")]
use crate::error::CStringDecodeError;
use core::convert::Infallible; use core::convert::Infallible;
use core::error::Error; use core::error::Error;
use core::fmt::{self, Display, Formatter}; use core::fmt::{self, Display, Formatter};
@ -48,9 +50,6 @@ pub enum GenericDecodeError {
/// A string contained a non-UTF-8 sequence. /// A string contained a non-UTF-8 sequence.
BadString(Utf8Error), BadString(Utf8Error),
/// A boolean was neither `false` nor `true`.
InvalidBool(BoolDecodeError),
/// A C-like string contained a null byte. /// A C-like string contained a null byte.
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(doc, doc(cfg(feature = "std")))] #[cfg_attr(doc, doc(cfg(feature = "std")))]
@ -60,7 +59,7 @@ pub enum GenericDecodeError {
NullInteger(NonZeroDecodeError), NullInteger(NonZeroDecodeError),
/// A statically-sized buffer was too small. /// A statically-sized buffer was too small.
SmallBuffer(SizeError), SmallBuffer(LengthError),
/// An unassigned discriminant value was encountered. /// An unassigned discriminant value was encountered.
/// ///
@ -79,29 +78,24 @@ pub enum GenericDecodeError {
impl Display for GenericDecodeError { impl Display for GenericDecodeError {
#[inline] #[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use GenericDecodeError::*;
match *self { match *self {
BadString(ref e) Self::BadString(ref e)
=> write!(f, "{e}"), => write!(f, "{e}"),
InvalidBool(ref e) Self::NullString(ref e)
=> write!(f, "{e}"), => write!(f, "{e}"),
NullString(ref e) Self::NullInteger(ref e)
=> write!(f, "{e}"), => write!(f, "{e}"),
NullInteger(ref e) Self::SmallBuffer(ref e)
=> write!(f, "{e}"), => write!(f, "{e}"),
SmallBuffer(ref e) Self::UnassignedDiscriminant { value }
=> write!(f, "{e}"),
UnassignedDiscriminant { value }
=> write!(f, "discriminant value `{value:#X} has not been assigned"), => write!(f, "discriminant value `{value:#X} has not been assigned"),
#[cfg(feature = "std")] #[cfg(feature = "std")]
NarrowSystemTime(ref e) Self::NarrowSystemTime(ref e)
=> write!(f, "{e}"), => write!(f, "{e}"),
} }
} }
@ -110,35 +104,24 @@ impl Display for GenericDecodeError {
impl Error for GenericDecodeError { impl Error for GenericDecodeError {
#[inline] #[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
use GenericDecodeError::*;
match *self { match *self {
BadString(ref e) => Some(e), Self::BadString(ref e) => Some(e),
InvalidBool(ref e) => Some(e),
#[cfg(feature = "std")] #[cfg(feature = "std")]
NullString(ref e) => Some(e), Self::NullString(ref e) => Some(e),
NullInteger(ref e) => Some(e), Self::NullInteger(ref e) => Some(e),
SmallBuffer(ref e) => Some(e), Self::SmallBuffer(ref e) => Some(e),
#[cfg(feature = "std")] #[cfg(feature = "std")]
NarrowSystemTime(ref e) => Some(e), Self::NarrowSystemTime(ref e) => Some(e),
_ => None, _ => None,
} }
} }
} }
impl From<BoolDecodeError> for GenericDecodeError {
#[inline(always)]
fn from(value: BoolDecodeError) -> Self {
Self::InvalidBool(value)
}
}
impl<L, I> From<CollectionDecodeError<L, I>> for GenericDecodeError impl<L, I> From<CollectionDecodeError<L, I>> for GenericDecodeError
where where
L: Into<Self>, L: Into<Self>,
@ -146,16 +129,25 @@ where
{ {
#[inline(always)] #[inline(always)]
fn from(value: CollectionDecodeError<L, I>) -> Self { fn from(value: CollectionDecodeError<L, I>) -> Self {
use CollectionDecodeError::*; use CollectionDecodeError as Error;
match value { match value {
Length(e) => e.into(), Error::BadLength(e) => e.into(),
Item(e) => e.into(), Error::BadItem(e) => e.into(),
} }
} }
} }
#[cfg(feature = "alloc")]
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl From<CStringDecodeError> for GenericDecodeError {
#[inline(always)]
fn from(value: CStringDecodeError) -> Self {
Self::NullString(value)
}
}
impl<D, F> From<EnumDecodeError<D, F>> for GenericDecodeError impl<D, F> From<EnumDecodeError<D, F>> for GenericDecodeError
where where
D: Decode<Error: Into<Self>> + PrimitiveDiscriminant, D: Decode<Error: Into<Self>> + PrimitiveDiscriminant,
@ -163,14 +155,14 @@ where
{ {
#[inline(always)] #[inline(always)]
fn from(value: EnumDecodeError<D, F>) -> Self { fn from(value: EnumDecodeError<D, F>) -> Self {
use EnumDecodeError::*; use EnumDecodeError as Error;
match value { match value {
InvalidDiscriminant(e) => e.into(), Error::InvalidDiscriminant(e) => e.into(),
UnassignedDiscriminant { value } => Self::UnassignedDiscriminant { value: value.to_u128() }, Error::UnassignedDiscriminant { value } => Self::UnassignedDiscriminant { value: value.to_u128() },
Field(e) => e.into(), Error::BadField(e) => e.into(),
} }
} }
} }
@ -178,6 +170,8 @@ where
impl From<Infallible> for GenericDecodeError { impl From<Infallible> for GenericDecodeError {
#[inline(always)] #[inline(always)]
fn from(_value: Infallible) -> Self { fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed
unsafe { unreachable_unchecked() } unsafe { unreachable_unchecked() }
} }
} }
@ -189,15 +183,6 @@ impl<I, E: Into<Self>> From<ItemDecodeError<I, E>> for GenericDecodeError {
} }
} }
#[cfg(feature = "std")]
#[cfg_attr(doc, doc(cfg(feature = "std")))]
impl From<CStringDecodeError> for GenericDecodeError {
#[inline(always)]
fn from(value: CStringDecodeError) -> Self {
Self::NullString(value)
}
}
impl From<NonZeroDecodeError> for GenericDecodeError { impl From<NonZeroDecodeError> for GenericDecodeError {
#[inline(always)] #[inline(always)]
fn from(value: NonZeroDecodeError) -> Self { fn from(value: NonZeroDecodeError) -> Self {
@ -205,9 +190,9 @@ impl From<NonZeroDecodeError> for GenericDecodeError {
} }
} }
impl From<SizeError> for GenericDecodeError { impl From<LengthError> for GenericDecodeError {
#[inline(always)] #[inline(always)]
fn from(value: SizeError) -> Self { fn from(value: LengthError) -> Self {
Self::SmallBuffer(value) Self::SmallBuffer(value)
} }
} }

View file

@ -1,25 +1,25 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::Encode; use crate::encode::Encode;
use crate::error::{ use crate::error::{
CollectionEncodeError, CollectionEncodeError,
EnumEncodeError, EnumEncodeError,
@ -36,7 +36,7 @@ use core::hint::unreachable_unchecked;
/// A decoding failed. /// A decoding failed.
/// ///
/// The intended use of this type is by [derived](derive@crate::Encode) implementations of [`Encode`](crate::Encode). /// The intended use of this type is by [derived](derive@crate::encode::Encode) implementations of [`Encode`](crate::encode::Encode).
/// Manual implementors are recommended to use a custom or less generic type for the sake of efficiency. /// Manual implementors are recommended to use a custom or less generic type for the sake of efficiency.
#[derive(Debug)] #[derive(Debug)]
#[must_use] #[must_use]
@ -55,31 +55,29 @@ pub enum GenericEncodeError {
impl Display for GenericEncodeError { impl Display for GenericEncodeError {
#[inline] #[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use GenericEncodeError::*; match *self {
Self::BadBorrow(ref e)
=> write!(f, "{e}"),
let e: &dyn Display = match *self { Self::LargeIsize(ref e)
BadBorrow(ref e) => e, => write!(f, "{e}"),
LargeIsize(ref e) => e, Self::LargeUsize(ref e)
=> write!(f, "{e}"),
LargeUsize(ref e) => e, }
};
e.fmt(f)
} }
} }
impl Error for GenericEncodeError { impl Error for GenericEncodeError {
#[inline] #[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
use GenericEncodeError::*;
match *self { match *self {
BadBorrow(ref e) => Some(e), Self::BadBorrow(ref e) => Some(e),
LargeIsize(ref e) => Some(e), Self::LargeIsize(ref e) => Some(e),
LargeUsize(ref e) => Some(e), Self::LargeUsize(ref e) => Some(e),
} }
} }
} }
@ -98,12 +96,12 @@ where
{ {
#[inline(always)] #[inline(always)]
fn from(value: CollectionEncodeError<L, I>) -> Self { fn from(value: CollectionEncodeError<L, I>) -> Self {
use CollectionEncodeError::*; use CollectionEncodeError as Error;
match value { match value {
Length(e) => e.into(), Error::BadLength(e) => e.into(),
Item(e) => e.into(), Error::BadItem(e) => e.into(),
} }
} }
} }
@ -115,12 +113,12 @@ where
{ {
#[inline(always)] #[inline(always)]
fn from(value: EnumEncodeError<D, F>) -> Self { fn from(value: EnumEncodeError<D, F>) -> Self {
use EnumEncodeError::*; use EnumEncodeError as Error;
match value { match value {
Discriminant(e) => e.into(), Error::BadDiscriminant(e) => e.into(),
Field(e) => e.into(), Error::BadField(e) => e.into(),
} }
} }
} }
@ -128,6 +126,8 @@ where
impl From<Infallible> for GenericEncodeError { impl From<Infallible> for GenericEncodeError {
#[inline(always)] #[inline(always)]
fn from(_value: Infallible) -> Self { fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed
unsafe { unreachable_unchecked() } unsafe { unreachable_unchecked() }
} }
} }

View file

@ -0,0 +1,54 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
// This file is part of oct.
//
// oct 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.
//
// oct 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 oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::error::Error;
use core::fmt::{self, Display, Formatter};
/// An input-related error.
///
/// This structure is mainly returned by the [`read`](crate::decode::Input::read) and [`read_into`](crate::decode::Input::read_into) methods in [`decode::Input`](crate::decode::Input).
#[derive(Debug)]
#[must_use]
pub struct InputError {
/// The total capacity of the output stream.
pub capacity: usize,
/// The cursor position of the requested read.
pub position: usize,
/// The requested amount of octets.
pub count: usize,
}
impl Display for InputError {
#[inline(always)]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(
f,
"cannot read ({}) bytes at ({}) from input stream with capacity of ({})",
self.count,
self.position,
self.capacity,
)
}
}
impl Error for InputError { }

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::error::Error; use core::error::Error;
@ -35,7 +35,13 @@ pub struct IsizeEncodeError(
impl Display for IsizeEncodeError { impl Display for IsizeEncodeError {
#[inline(always)] #[inline(always)]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "signed size value ({}) cannot be serialised: must be in the range ({}) to ({})", self.0, i16::MIN, i16::MAX) write!(
f,
"signed size value ({}) cannot be serialised: must be in the range ({}) to ({})",
self.0,
i16::MIN,
i16::MAX,
)
} }
} }

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::convert::Infallible; use core::convert::Infallible;

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::convert::Infallible; use core::convert::Infallible;

View file

@ -1,49 +1,50 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::error::Error; use core::error::Error;
use core::fmt::{self, Display, Formatter}; use core::fmt::{self, Display, Formatter};
/// A fixed-size buffer was too small. /// A collection buffer was too small to contain all of its elements.
/// ///
/// Some data types use a statically-sized buffer whilst still allowing for partial usage of this buffer (e.g. [`SizedSlice`](crate::SizedSlice)). /// Some data types use a statically-sized buffer whilst still allowing for partial usage of this buffer (e.g. [`SizedSlice`](crate::SizedSlice)).
/// These types should return this error in cases where their size limit has exceeded.
/// ///
/// Taking `SizedSlice` as an example, it encodes its actual length before encoding each of its elements. /// Taking [`SizedSlice`](crate::SizedSlice) as an example, it encodes its actual length before encoding its elements.
/// It is allowed for any smaller-sized `SizedSlice` instance to decode a larger-sized encoding **if** the actual length still fits. /// It is allowed for any smaller-sized `SizedSlice` instance to decode a larger-sized encoding **if** the actual length is still within bounds.
/// If not, then this error type is used to denote the error state. /// Otherwise, this error type is used to denote the error state.
#[derive(Debug)] #[derive(Debug)]
#[must_use] #[must_use]
pub struct SizeError { pub struct LengthError {
/// The total capacity of the buffer. /// The total capacity of the buffer.
pub cap: usize, pub capacity: usize,
/// The required amount of elements. /// The required amount of elements.
pub len: usize, pub len: usize,
} }
impl Display for SizeError { impl Display for LengthError {
#[inline(always)] #[inline(always)]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "collection of size ({}) cannot hold ({}) elements", self.cap, self.len) write!(f, "collection of size ({}) cannot hold ({}) elements", self.capacity, self.len)
} }
} }
impl Error for SizeError { } impl Error for LengthError { }

View file

@ -1,45 +1,46 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
//! Error variants. //! Error variants.
//! //!
//! This module defines the error types used by Librum. //! This module defines the error types used by oct.
//! All of these types define (at least conditionally) the [`Error`](core::error::Error) trait. //! All of these types define (at least conditionally) the [`Error`](core::error::Error) trait.
use crate::use_mod; use crate::use_mod;
use_mod!(pub bool_decode_error);
use_mod!(pub char_decode_error); use_mod!(pub char_decode_error);
use_mod!(pub collection_decode_error); use_mod!(pub collection_decode_error);
use_mod!(pub collection_encode_error); use_mod!(pub collection_encode_error);
use_mod!(pub enum_encode_error);
use_mod!(pub enum_decode_error); use_mod!(pub enum_decode_error);
use_mod!(pub enum_encode_error);
use_mod!(pub generic_decode_error); use_mod!(pub generic_decode_error);
use_mod!(pub generic_encode_error); use_mod!(pub generic_encode_error);
use_mod!(pub input_error);
use_mod!(pub isize_encode_error); use_mod!(pub isize_encode_error);
use_mod!(pub item_decode_error); use_mod!(pub item_decode_error);
use_mod!(pub item_encode_error); use_mod!(pub item_encode_error);
use_mod!(pub length_error);
use_mod!(pub non_zero_decode_error); use_mod!(pub non_zero_decode_error);
use_mod!(pub output_error);
use_mod!(pub ref_cell_encode_error); use_mod!(pub ref_cell_encode_error);
use_mod!(pub size_error);
use_mod!(pub string_error); use_mod!(pub string_error);
use_mod!(pub usize_encode_error); use_mod!(pub usize_encode_error);
use_mod!(pub utf16_error); use_mod!(pub utf16_error);

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::error::Error; use core::error::Error;
@ -24,7 +24,7 @@ use core::fmt::{self, Display, Formatter};
/// A non-zero integer could not be decoded. /// A non-zero integer could not be decoded.
/// ///
/// The implementations of [`Decode`](crate::Decode) for <code>[NonZero](core::num::NonZero)&lt;T&gt;</code> yield this error type if decoding `T` yields zero. /// The implementations of [`Decode`](crate::decode::Decode) for <code>[NonZero](core::num::NonZero)&lt;T&gt;</code> yield this error type if decoding `T` yields zero.
#[derive(Debug)] #[derive(Debug)]
pub struct NonZeroDecodeError; pub struct NonZeroDecodeError;

View file

@ -0,0 +1,54 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
// This file is part of oct.
//
// oct 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.
//
// oct 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 oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::error::Error;
use core::fmt::{self, Display, Formatter};
#[derive(Debug)]
#[must_use]
/// An output-related error
///
/// This structure is mainly returned by the [`write`](crate::encode::Output::write) method in [`encode::Output`](crate::encode::Output).
pub struct OutputError {
/// The total capacity of the output stream.
pub capacity: usize,
/// The cursor position of the requested write.
pub position: usize,
/// The requested amount of octets.
pub count: usize,
}
impl Display for OutputError {
#[inline(always)]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(
f,
"cannot write ({}) bytes at ({}) to output stream with capacity of ({})",
self.count,
self.position,
self.capacity,
)
}
}
impl Error for OutputError { }

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::cell::BorrowError; use core::cell::BorrowError;
@ -25,28 +25,26 @@ use core::fmt::{self, Display, Formatter};
/// A reference cell could not be encoded. /// A reference cell could not be encoded.
/// ///
/// The implementation of <code>&lt;[RefCell](core::cell::RefCell)&lt;T&gt; as [Encode](crate::Encode)&gt;::[encode](crate::Encode::encode)</code> will first attempt to call <code>RefCell::[borrow](core::cell::RefCell::borrow)</code>. /// The implementation of <code>&lt;[RefCell](core::cell::RefCell)&lt;T&gt; as [Encode](crate::encode::Encode)&gt;::[encode](crate::encode::Encode::encode)</code> will first attempt to call <code>RefCell::[borrow](core::cell::RefCell::borrow)</code>.
/// If this call fails, then the returned error is again returned as a [`Borrow`](Self::Borrow) instance. /// If this call fails, then the returned error is again returned as a [`BadBorrow`](Self::BadBorrow) instance.
/// If the following call to <code>T::encode</code> fails instead, then the error returned from that call is passed on as a [`Value`](Self::Value) instance. /// If the following call to <code>T::encode</code> fails instead, then the error returned from that call is passed on as a [`BadValue`](Self::BadValue) instance.
#[derive(Debug)] #[derive(Debug)]
#[must_use] #[must_use]
pub enum RefCellEncodeError<E> { pub enum RefCellEncodeError<E> {
/// The reference cell could not be borrowed. /// The reference cell could not be borrowed.
Borrow(BorrowError), BadBorrow(BorrowError),
/// The contained value could not be encoded. /// The contained value could not be encoded.
Value(E), BadValue(E),
} }
impl<E: Display> Display for RefCellEncodeError<E> { impl<E: Display> Display for RefCellEncodeError<E> {
#[inline] #[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use RefCellEncodeError::*;
let e: &dyn Display = match *self { let e: &dyn Display = match *self {
Borrow(ref e) => e, Self::BadBorrow(ref e) => e,
Value(ref e) => e, Self::BadValue(ref e) => e,
}; };
write!(f, "unable to encode reference cell: {e}") write!(f, "unable to encode reference cell: {e}")
@ -56,12 +54,10 @@ impl<E: Display> Display for RefCellEncodeError<E> {
impl<E: Error + 'static> Error for RefCellEncodeError<E> { impl<E: Error + 'static> Error for RefCellEncodeError<E> {
#[inline(always)] #[inline(always)]
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
use RefCellEncodeError::*;
match *self { match *self {
Borrow(ref e) => Some(e), Self::BadBorrow(ref e) => Some(e),
Value(ref e) => Some(e) Self::BadValue(ref e) => Some(e)
} }
} }
} }

View file

@ -1,25 +1,25 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::error::{SizeError, Utf16Error, Utf8Error}; use crate::error::{LengthError, Utf16Error, Utf8Error};
use core::error::Error; use core::error::Error;
use core::fmt::{self, Display, Formatter}; use core::fmt::{self, Display, Formatter};
@ -36,22 +36,20 @@ pub enum StringError {
BadUtf8(Utf8Error), BadUtf8(Utf8Error),
/// A fixed-size buffer was too small. /// A fixed-size buffer was too small.
SmallBuffer(SizeError), SmallBuffer(LengthError),
} }
impl Display for StringError { impl Display for StringError {
#[inline] #[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use StringError::*;
match *self { match *self {
BadUtf16(ref e) Self::BadUtf16(ref e)
=> write!(f, "bad utf-16: {e}"), => write!(f, "bad utf-16: {e}"),
BadUtf8(ref e) Self::BadUtf8(ref e)
=> write!(f, "bad utf-8: {e}"), => write!(f, "bad utf-8: {e}"),
SmallBuffer(ref e) Self::SmallBuffer(ref e)
=> write!(f, "buffer too small: {e}"), => write!(f, "buffer too small: {e}"),
} }
} }
@ -60,14 +58,12 @@ impl Display for StringError {
impl Error for StringError { impl Error for StringError {
#[inline] #[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
use StringError::*;
match *self { match *self {
BadUtf16(ref e) => Some(e), Self::BadUtf16(ref e) => Some(e),
BadUtf8(ref e) => Some(e), Self::BadUtf8(ref e) => Some(e),
SmallBuffer(ref e) => Some(e), Self::SmallBuffer(ref e) => Some(e),
} }
} }
} }

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::error::Error; use core::error::Error;

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::error::Error; use core::error::Error;
@ -35,7 +35,12 @@ pub struct UsizeEncodeError(
impl Display for UsizeEncodeError { impl Display for UsizeEncodeError {
#[inline(always)] #[inline(always)]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "unsigned size value ({}) cannot be serialised: must be at most ({})", self.0, u16::MAX) write!(
f,
"unsigned size value ({}) cannot be serialised: must be at most ({})",
self.0,
u16::MAX,
)
} }
} }

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::error::Error; use core::error::Error;

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use core::error::Error; use core::error::Error;

View file

@ -1,29 +1,29 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
#![doc(html_logo_url = "https://gitlab.com/bjoernager/librum/-/raw/master/doc-icon.svg")] #![doc(html_logo_url = "https://gitlab.com/bjoernager/oct/-/raw/master/doc-icon.svg")]
//! Librum is a Rust crate for cheaply serialising (encoding) and deserialising (decoding) data structures into binary streams //! oct 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). //! 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 directly translating into binary encodings (whilst the mentioned crates specifically use Serde as a middle layer).
//! The original goal of this project was specifically to guarantee size constraints for encodings on a per-type basis at compile-time. //! The original goal of this project was specifically to guarantee size constraints for encodings on a per-type basis at compile-time.
//! Therefore, this crate may be more suited for networking or other cases where many allocations are unwanted. //! Therefore, this crate may be more suited for networking or other cases where many allocations are unwanted.
//! //!
@ -34,24 +34,25 @@
//! //!
//! # Performance //! # Performance
//! //!
//! As Librum is optimised exclusively for a single, binary format, it *may* outperform other libraries that are more generic in nature. //! As oct is optimised exclusively for a single, binary format, it *may* outperform other libraries that are more generic in nature.
//! //!
//! The `librum-benchmarks` binary compares multiple scenarios using Librum and other, similar crates. //! The `oct-benchmarks` binary compares multiple scenarios using oct and other, similar crates.
//! According to my runs on an AMD Ryzen 7 3700X with default settings, these benchmarks indicate that Librum usually outperforms the other tested crates -- as demonstrated in the following table: //! According to my runs on an AMD Ryzen 7 3700X with default settings, these benchmarks indicate that oct usually outperforms the other tested crates -- as demonstrated in the following table:
//! //!
//! | Benchmark | [Bincode] | [Borsh] | Librum | [Postcard] | //! | Benchmark | [Bincode] | [Borsh] | oct | [Postcard] |
//! | :--------------------------------- | --------: | ------: | ------: | ---------: | //! | :--------------------------------- | --------: | ------: | ------: | ---------: |
//! | `encode_u8` | 1.004 | 0.947 | 0.806 | 0.972 | //! | `encode_u8` | 0.968 | 0.857 | 0.733 | 0.979 |
//! | `encode_u32` | 1.130 | 1.084 | 0.749 | 2.793 | //! | `encode_u32` | 1.065 | 0.999 | 0.730 | 2.727 |
//! | `encode_u128` | 2.340 | 2.328 | 1.543 | 6.380 | //! | `encode_u128` | 2.168 | 2.173 | 1.510 | 6.246 |
//! | `encode_struct_unit` | 0.000 | 0.000 | 0.000 | 0.000 | //! | `encode_struct_unit` | 0.000 | 0.000 | 0.000 | 0.000 |
//! | `encode_struct_unnamed` | 1.218 | 1.160 | 0.838 | 2.392 | //! | `encode_struct_unnamed` | 1.241 | 1.173 | 0.823 | 3.350 |
//! | `encode_struct_named` | 3.077 | 1.501 | 0.975 | 3.079 | //! | `encode_struct_named` | 3.079 | 1.507 | 0.973 | 3.082 |
//! | `encode_enum_unit` | 0.260 | 0.310 | 0.000 | 0.303 | //! | `encode_enum_unit` | 0.246 | 0.297 | 0.000 | 0.295 |
//! | `decode_u8` | 1.116 | 1.106 | 1.110 | 1.102 | //! | `decode_u8` | 0.942 | 0.962 | 0.922 | 0.923 |
//! | `decode_non_zero_u8` | 1.228 | 1.236 | 1.269 | 1.263 | //! | `decode_non_zero_u8` | 1.126 | 1.159 | 1.127 | 1.160 |
//! | **Total time** &#8594; | 11.373 | 9.672 | 7.291 | 18.284 | //! | `decode_bool` | 1.040 | 1.099 | 1.055 | 1.177 |
//! | **Total deviation (p.c.)** &#8594; | +56 | +33 | ±0 | +150 | //! | **Total time** &#8594; | 11.873 | 10.225 | 7.873 | 18.939 |
//! | **Total deviation (p.c.)** &#8594; | +51 | +30 | ±0 | +141 |
//! //!
//! [Bincode]: https://crates.io/crates/bincode/ //! [Bincode]: https://crates.io/crates/bincode/
//! [Borsh]: https://crates.io/crates/borsh/ //! [Borsh]: https://crates.io/crates/borsh/
@ -59,9 +60,9 @@
//! //!
//! All quantities are measured in seconds unless otherwise noted. //! All quantities are measured in seconds unless otherwise noted.
//! //!
//! Currently, Librum's weakest point seems to be decoding. //! Currently, oct's weakest point seems to be decoding.
//! Please note that I myself find large (relatively speaking) inconsistencies between runs in these last two benchmarks. //! Please note that I myself find large (relatively speaking) inconsistencies between runs in these last two benchmarks.
//! Do feel free to conduct your own tests of Librum. //! Do feel free to conduct your own tests of oct.
//! //!
//! # Data model //! # Data model
//! //!
@ -78,16 +79,18 @@
//! //!
//! # Usage //! # Usage
//! //!
//! This crate revolves around the [`Encode`] and [`Decode`] traits, both of which handle conversions to and from byte streams. //! This crate revolves around the [`Encode`](encode::Encode) and [`Decode`](decode::Decode) traits, both of which handle conversions to and from byte streams.
//! //!
//! Many standard types come implemented with Librum, including most primitives as well as some standard library types such as [`Option`] and [`Result`]. //! Many standard types come implemented with oct, 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. //! Some [features](#feature-flags) enable an extended set of implementations.
//! //!
//! It is recommended in most cases to simply derive these two traits for user-defined 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 user-defined types (although this is only supported with enumerations and structures -- not untagged unions).
//! Here, each field is *chained* according to declaration order: //! Here, each field is *chained* according to declaration order:
//! //!
//! ``` //! ```
//! use librum::{Buf, Decode, Encode}; //! use oct::Slot;
//! use oct::decode::Decode;
//! use oct::encode::Encode;
//! //!
//! #[derive(Debug, Decode, Encode, PartialEq)] //! #[derive(Debug, Decode, Encode, PartialEq)]
//! struct Ints { //! struct Ints {
@ -106,7 +109,7 @@
//! value4: 0x1E_1D_1C_1B_1A_19_18_17_16_15_14_13_12_11_10_0F, //! value4: 0x1E_1D_1C_1B_1A_19_18_17_16_15_14_13_12_11_10_0F,
//! }; //! };
//! //!
//! let mut buf = Buf::with_capacity(0x100); //! let mut buf = Slot::with_capacity(0x100);
//! //!
//! buf.write(VALUE).unwrap(); //! buf.write(VALUE).unwrap();
//! //!
@ -127,20 +130,20 @@
//! //!
//! ## Buffer types //! ## Buffer types
//! //!
//! The [`Encode`] and [`Decode`] traits both rely on streams for carrying the manipulated bytes. //! The [`Encode`](encode::Encode) and [`Decode`](decode::Decode) traits both rely on streams for carrying the manipulated bytes.
//! //!
//! These streams are separated into two type: [*O-streams*](OStream) (output streams) and [*i-streams*](IStream) (input streams). //! These streams are separated into two type: [*output streams*](encode::Output) and [*input streams*](decode::Input).
//! The [`Buf`] type can be used to handle these streams. //! The [`Slot`] type can be used to handle these streams.
//! //!
//! ## Encoding //! ## 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 `Output` object:
//! //!
//! ``` //! ```
//! use librum::{Encode, OStream, SizedEncode}; //! use oct::encode::{Encode, Output, SizedEncode};
//! //!
//! let mut buf = [0x00; char::MAX_ENCODED_SIZE]; //! let mut buf = [0x00; char::MAX_ENCODED_SIZE];
//! let mut stream = OStream::new(&mut buf); //! let mut stream = Output::new(&mut buf);
//! //!
//! 'Ж'.encode(&mut stream).unwrap(); //! 'Ж'.encode(&mut stream).unwrap();
//! //!
@ -150,10 +153,10 @@
//! Streams can also be used to chain multiple objects together: //! Streams can also be used to chain multiple objects together:
//! //!
//! ``` //! ```
//! use librum::{Encode, OStream, SizedEncode}; //! use oct::encode::{Encode, Output, SizedEncode};
//! //!
//! let mut buf = [0x0; char::MAX_ENCODED_SIZE * 0x5]; //! let mut buf = [0x0; char::MAX_ENCODED_SIZE * 0x5];
//! let mut stream = OStream::new(&mut buf); //! let mut stream = Output::new(&mut buf);
//! //!
//! // Note: For serialising multiple characters, the //! // Note: For serialising multiple characters, the
//! // `String` and `SizedStr` types are usually //! // `String` and `SizedStr` types are usually
@ -172,31 +175,31 @@
//! ]); //! ]);
//! ``` //! ```
//! //!
//! 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. //! If the encoded type additionally implements [`SizedEncode`](encode::SizedEncode), then the maximum size of any encoding is guaranteed with the [`MAX_ENCODED_SIZE`](encode::SizedEncode::MAX_ENCODED_SIZE) constant.
//! //!
//! ## Decoding //! ## Decoding
//! //!
//! Decoding works with a similar syntax to encoding. //! Decoding works with a similar syntax to encoding.
//! To decode a byte array, simply call the [`decode`](Decode::decode) method with an [`IStream`] object: //! To decode a byte array, simply call the [`decode`](decode::Decode::decode) method with an [`Input`](decode::Input) object:
//! //!
//! ``` //! ```
//! use librum::{Decode, IStream}; //! use oct::decode::{Decode, Input};
//! //!
//! let data = [0x54, 0x45]; //! let data = [0x54, 0x45];
//! let mut stream = IStream::new(&data); //! let mut stream = Input::new(&data);
//! //!
//! assert_eq!(u16::decode(&mut stream).unwrap(), 0x4554); //! assert_eq!(u16::decode(&mut stream).unwrap(), 0x4554);
//! //!
//! // Data can theoretically be reinterpretred: //! // Data can theoretically be reinterpretred:
//! //!
//! stream = IStream::new(&data); //! stream = Input::new(&data);
//! //!
//! assert_eq!(u8::decode(&mut stream).unwrap(), 0x54); //! assert_eq!(u8::decode(&mut stream).unwrap(), 0x54);
//! assert_eq!(u8::decode(&mut stream).unwrap(), 0x45); //! assert_eq!(u8::decode(&mut stream).unwrap(), 0x45);
//! //!
//! // Including as tuples: //! // Including as tuples:
//! //!
//! stream = IStream::new(&data); //! stream = Input::new(&data);
//! //!
//! assert_eq!(<(u8, u8)>::decode(&mut stream).unwrap(), (0x54, 0x45)); //! assert_eq!(<(u8, u8)>::decode(&mut stream).unwrap(), (0x54, 0x45));
//! ``` //! ```
@ -206,7 +209,9 @@
//! A UDP server/client for geographic data: //! A UDP server/client for geographic data:
//! //!
//! ``` //! ```
//! use librum::{Buf, Encode, Decode, SizedEncode}; //! use oct::Slot;
//! use oct::decode::Decode;
//! use oct::encode::{Encode, SizedEncode};
//! use std::io; //! use std::io;
//! use std::net::{SocketAddr, ToSocketAddrs, UdpSocket}; //! use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
//! use std::thread::spawn; //! use std::thread::spawn;
@ -242,8 +247,8 @@
//! struct Party { //! struct Party {
//! pub socket: UdpSocket, //! pub socket: UdpSocket,
//! //!
//! pub request_buf: Buf::<Request>, //! pub request_buf: Slot::<Request>,
//! pub response_buf: Buf::<Response>, //! pub response_buf: Slot::<Response>,
//! } //! }
//! //!
//! impl Party { //! impl Party {
@ -253,8 +258,8 @@
//! let this = Self { //! let this = Self {
//! socket, //! socket,
//! //!
//! request_buf: Buf::new(), //! request_buf: Slot::new(),
//! response_buf: Buf::new(), //! response_buf: Slot::new(),
//! }; //! };
//! //!
//! Ok(this) //! Ok(this)
@ -307,28 +312,28 @@
//! //!
//! # Feature flags //! # Feature flags
//! //!
//! Librum defines the following features: //! oct defines the following features:
//! //!
//! * *`alloc`: Enables the [`Buf`] type and implementations for e.g. [`Box`](alloc::boxed::Box) and [`Arc`](alloc::sync::Arc) //! * *`alloc`: Enables the [`Slot`] 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 //! * *`proc-macro`: Pulls the procedural macros from the [`oct-macros`](https://crates.io/crates/oct-macros/) crate
//! * *`std`: Enables implementations for types such as [`Mutex`](std::sync::Mutex) and [`RwLock`](std::sync::RwLock) //! * *`std`: Enables implementations for types such as [`Mutex`](std::sync::Mutex) and [`RwLock`](std::sync::RwLock)
//! //!
//! Features marked with * are enabled by default. //! Features marked with * are enabled by default.
//! //!
//! # Documentation //! # Documentation
//! //!
//! Librum has its documentation written in-source for use by `rustdoc`. //! oct 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. //! See [Docs.rs](https://docs.rs/oct/latest/oct/) for an on-line, rendered instance.
//! //!
//! Currently, these docs make use of some unstable features for the sake of readability. //! Currently, these docs make use of some unstable features for the sake of readability.
//! The nightly toolchain is therefore required when rendering them. //! The nightly toolchain is therefore required when rendering them.
//! //!
//! # Contribution //! # Contribution
//! //!
//! Librum does not accept source code contributions at the moment. //! oct does not accept source code contributions at the moment.
//! This is a personal choice by the maintainer and may be undone in the future. //! 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/librum/issues/) or (preferably) [GitHub](https://github.com/bjoernager/librum/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/oct/issues/) or (preferably) [GitHub](https://github.com/bjoernager/oct/issues/) if you feel the need to express any concerns over the project.
//! //!
//! # Copyright & Licence //! # Copyright & Licence
//! //!
@ -344,13 +349,13 @@
#![no_std] #![no_std]
#![warn(missing_docs)]
#![cfg_attr(doc, allow(internal_features))] #![cfg_attr(doc, allow(internal_features))]
#![cfg_attr(doc, feature(doc_cfg, rustdoc_internals))] #![cfg_attr(doc, feature(doc_cfg, rustdoc_internals))]
#![deny(missing_docs)]
// For use in macros: // For use in macros:
extern crate self as librum; extern crate self as oct;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
extern crate alloc; extern crate alloc;
@ -358,116 +363,6 @@ extern crate alloc;
#[cfg(feature = "std")] #[cfg(feature = "std")]
extern crate std; extern crate std;
/// Implements [`Decode`] for the provided type.
///
/// This macro assumes the same format used by the equivalent [`Encode`](derive@Encode) macro.
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc, doc(cfg(feature = "proc-macro")))]
#[doc(inline)]
pub use librum_macros::Decode;
/// Implements [`Encode`] for the provided type.
///
/// This derive macro assumes that all fields implement <code>Encode&lt;[Error]: [Into]&lt;[GenericEncodeError]&gt;&gt;</code>.
/// If this is **not** the case, then the trait should be implemented manually instead.
///
/// [Error]: Encode::Error
/// [GenericEncodeError]: crate::error::GenericEncodeError
///
/// Do also consider deriving [`SizedEncode`](derive@SizedEncode) -- if possible.
///
/// # Structs
///
/// For structures, each element is chained in **order of declaration.**
/// If the structure is a unit structure (i.e. it has *no* fields) then it is encoded equivalently to the [unit] type.
///
/// For example, the following struct will encode its field `foo` followed by `bar`:
///
/// ```
/// use librum::Encode;
///
/// #[derive(Encode)]
/// struct FooBar {
/// pub foo: char,
/// pub bar: char,
/// }
/// ```
///
/// This should be kept in mind when changing the structure's declarationm as doing so may invalidate previous encodings.
///
/// The [`Error`](Encode::Error) type will in all cases just be `GenericEncodeError`.
///
/// # Enums
///
/// Enumerations encode like structures except that each variant additionally encodes a unique discriminant.
///
/// By default, each discriminant is assigned from the range 0 to infinite, to the extend allowed by the [`isize`] type and its encoding (as which **all** discriminants are encoded).
/// A custom discriminant may be set instead by assigning the variant an integer constant.
/// Unspecified discriminants then increment the previous variant's discriminant:
///
/// ```
/// use librum::{Buf, Encode};
///
/// #[derive(Encode)]
/// enum Num {
/// Two = 0x2,
///
/// Three,
///
/// Zero = 0x0,
///
/// One,
/// }
///
/// let mut buf = Buf::with_capacity(size_of::<i16>());
///
/// buf.write(Num::Zero).unwrap();
/// assert_eq!(buf, [0x00, 0x00].as_slice());
///
/// buf.write(Num::One).unwrap();
/// assert_eq!(buf, [0x01, 0x00].as_slice());
///
/// buf.write(Num::Two).unwrap();
/// assert_eq!(buf, [0x02, 0x00].as_slice());
///
/// buf.write(Num::Three).unwrap();
/// assert_eq!(buf, [0x03, 0x00].as_slice());
/// ```
///
/// Variants with fields are encoded exactly like structures.
/// That is, each field is chained in order of declaration.
///
/// For error handling, the `Error` type is defined as:
///
/// <code>[EnumEncodeError]&lt;&lt;Repr as Encode&gt;::Error, GenericEncodeError&gt;</code>,
///
/// [EnumEncodeError]: crate::error::GenericEncodeError
///
/// wherein `Repr` is the enumeration's representation.
///
/// # Unions
///
/// Unions cannot derive `Encode` due to the uncertainty of their contents.
/// The trait should therefore be implemented manually for such types.
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc, doc(cfg(feature = "proc-macro")))]
#[doc(inline)]
pub use librum_macros::Encode;
/// Implements [`Encode`](trait@Encode) using the default implementation.
///
/// For simple structures, the value of [`MAX_ENCODED_SIZE`](SizedEncode::MAX_ENCODED_SIZE) is set as the combined value of <code>T*n*::MAX_ENCODED_SIZE</code> wherein <code>T*n*</code> is the type of each field.
///
/// For enumerations, the value is set such that each variant is treated like a structure (with the discriminant as an extra field) and where the variant that produces the largest `MAX_ENCODED_SIZE` is chosen.
///
/// As untagged unions cannot derive `Encode`, `SizedEncode` also cannot be derived for them.
///
/// Do remember that deriving this trait is only recommended
#[cfg(feature = "proc-macro")]
#[cfg_attr(doc, doc(cfg(feature = "proc-macro")))]
#[doc(inline)]
pub use librum_macros::SizedEncode;
macro_rules! use_mod { macro_rules! use_mod {
($vis:vis $name:ident$(,)?) => { ($vis:vis $name:ident$(,)?) => {
mod $name; mod $name;
@ -476,18 +371,14 @@ macro_rules! use_mod {
} }
pub(crate) use use_mod; pub(crate) use use_mod;
use_mod!(pub decode);
use_mod!(pub decode_borrowed);
use_mod!(pub encode);
use_mod!(pub i_stream);
use_mod!(pub o_stream);
use_mod!(pub primitive_discriminant); use_mod!(pub primitive_discriminant);
use_mod!(pub sized_encode);
use_mod!(pub sized_iter); use_mod!(pub sized_iter);
use_mod!(pub sized_slice); use_mod!(pub sized_slice);
use_mod!(pub sized_str); use_mod!(pub sized_str);
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use_mod!(pub buf); use_mod!(pub slot);
pub mod decode;
pub mod encode;
pub mod error; pub mod error;

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
mod sealed { mod sealed {
@ -46,16 +46,15 @@ pub trait PrimitiveDiscriminant: Copy + SealedPrimitiveDiscriminant + Sized { }
macro_rules! impl_primitive_discriminant { macro_rules! impl_primitive_discriminant {
($ty:ty) => { ($ty:ty) => {
impl ::librum::SealedPrimitiveDiscriminant for $ty { impl ::oct::SealedPrimitiveDiscriminant for $ty {
#[allow(clippy::cast_lossless)] #[allow(clippy::cast_lossless)]
#[inline(always)] #[inline(always)]
#[must_use]
fn to_u128(self) -> u128 { fn to_u128(self) -> u128 {
self as u128 self as u128
} }
} }
impl ::librum::PrimitiveDiscriminant for $ty { } impl ::oct::PrimitiveDiscriminant for $ty { }
}; };
} }

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
#[cfg(test)] #[cfg(test)]
@ -89,7 +89,7 @@ impl<T, const N: usize> AsRef<[T]> for SizedIter<T, N> {
impl<T: Clone, const N: usize> Clone for SizedIter<T, N> { impl<T: Clone, const N: usize> Clone for SizedIter<T, N> {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
let mut buf: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut buf = [const { MaybeUninit::<T>::uninit() };N];
let Self { pos, len, .. } = *self; let Self { pos, len, .. } = *self;
let start = pos; let start = pos;

View file

@ -1,25 +1,25 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use librum::{SizedSlice, SizedStr}; use oct::{SizedSlice, SizedStr};
#[test] #[test]
fn test_sized_iter_clone() { fn test_sized_iter_clone() {

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::SizedSlice; use crate::SizedSlice;

View file

@ -1,50 +1,44 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::{ use crate::SizedSlice;
Decode, use crate::decode::{Decode, DecodeBorrowed, Input};
DecodeBorrowed, use crate::encode::{Encode, Output, SizedEncode};
Encode, use crate::error::{CollectionDecodeError, ItemDecodeError, LengthError};
IStream,
OStream,
SizedEncode,
SizedSlice
};
use crate::error::{CollectionDecodeError, ItemDecodeError, SizeError};
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
impl<T: Decode, const N: usize> Decode for SizedSlice<T, N> { impl<T: Decode, const N: usize> Decode for SizedSlice<T, N> {
type Error = CollectionDecodeError<SizeError, ItemDecodeError<usize, T::Error>>; type Error = CollectionDecodeError<LengthError, ItemDecodeError<usize, T::Error>>;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap(); let len = Decode::decode(input).unwrap();
if len > N { return Err(CollectionDecodeError::Length(SizeError { cap: N, len })) }; if len > N { return Err(CollectionDecodeError::BadLength(LengthError { capacity: N, len })) };
let mut buf: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut buf = [const { MaybeUninit::<T>::uninit() };N];
for (i, slot) in buf.iter_mut().enumerate() { for (i, slot) in buf.iter_mut().enumerate() {
let v = Decode::decode(stream) let v = Decode::decode(input)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?; .map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
slot.write(v); slot.write(v);
} }
@ -59,8 +53,8 @@ impl<T: Encode, const N: usize> Encode for SizedSlice<T, N> {
type Error = <[T] as Encode>::Error; type Error = <[T] as Encode>::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_slice().encode(stream) self.as_slice().encode(output)
} }
} }

View file

@ -1,26 +1,26 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::SizedSlice; use crate::SizedSlice;
use crate::error::SizeError; use crate::error::LengthError;
use core::borrow::{Borrow, BorrowMut}; use core::borrow::{Borrow, BorrowMut};
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
@ -203,7 +203,7 @@ impl<T, const N: usize> From<[T; N]> for SizedSlice<T, N> {
} }
impl<T: Clone, const N: usize> TryFrom<&[T]> for SizedSlice<T, N> { impl<T: Clone, const N: usize> TryFrom<&[T]> for SizedSlice<T, N> {
type Error = SizeError; type Error = LengthError;
#[inline(always)] #[inline(always)]
fn try_from(value: &[T]) -> Result<Self, Self::Error> { fn try_from(value: &[T]) -> Result<Self, Self::Error> {

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::{SizedIter, SizedSlice}; use crate::{SizedIter, SizedSlice};
@ -29,7 +29,7 @@ impl<T, const N: usize> FromIterator<T> for SizedSlice<T, N> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut iter = iter.into_iter(); let mut iter = iter.into_iter();
let mut buf: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut buf = [const { MaybeUninit::<T>::uninit() };N];
let mut len = 0x0; let mut len = 0x0;
for item in &mut buf { for item in &mut buf {

View file

@ -1,28 +1,28 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::error::SizeError; use crate::error::LengthError;
use core::fmt::{self, Debug, Formatter}; use core::fmt::{self, Debug, Formatter};
use core::hash::{Hash, Hasher}; use core::hash::{Hash, Hasher};
@ -31,6 +31,9 @@ use core::ops::{Index, IndexMut};
use core::ptr::{copy_nonoverlapping, null, null_mut}; use core::ptr::{copy_nonoverlapping, null, null_mut};
use core::slice::SliceIndex; use core::slice::SliceIndex;
// Encode/decode facilities:
mod code;
// Conversion facilities: // Conversion facilities:
mod conv; mod conv;
@ -40,12 +43,9 @@ mod cmp;
// Iterator facilities: // Iterator facilities:
mod iter; mod iter;
// Encode/decode facilities:
mod serdes;
/// Stack-allocated vector with maximum length. /// Stack-allocated vector with maximum length.
/// ///
/// This type is intended as a [sized-encodable](crate::SizedEncode) alternative to [`Vec`](alloc::vec::Vec) -- for cases where [arrays](array) may not be wanted -- as well as a [decodable](crate::Decode) alternative to normal [slices](slice). /// This type is intended as a [sized-encodable](crate::encode::SizedEncode) alternative to [`Vec`](alloc::vec::Vec) -- for cases where [arrays](array) may not be wanted -- as well as a [decodable](crate::decode::Decode) alternative to normal [slices](slice).
/// ///
/// Note that this type is immutable in the sense that it does **not** define methods like `push` and `pop`, unlike `Vec`. /// Note that this type is immutable in the sense that it does **not** define methods like `push` and `pop`, unlike `Vec`.
/// ///
@ -56,7 +56,7 @@ mod serdes;
/// All instances of this type with the same `T` and `N` also have the exact same layout: /// All instances of this type with the same `T` and `N` also have the exact same layout:
/// ///
/// ``` /// ```
/// use librum::SizedSlice; /// use oct::SizedSlice;
/// ///
/// let vec0 = SizedSlice::<u8, 0x4>::try_from([0x3].as_slice()).unwrap(); /// let vec0 = SizedSlice::<u8, 0x4>::try_from([0x3].as_slice()).unwrap();
/// let vec1 = SizedSlice::<u8, 0x4>::try_from([0x3, 0x2].as_slice()).unwrap(); /// let vec1 = SizedSlice::<u8, 0x4>::try_from([0x3, 0x2].as_slice()).unwrap();
@ -201,11 +201,11 @@ impl<T, const N: usize> SizedSlice<T, N> {
impl<T: Clone, const N: usize> SizedSlice<T, N> { impl<T: Clone, const N: usize> SizedSlice<T, N> {
/// Constructs an empty, fixed-size vector. /// Constructs an empty, fixed-size vector.
#[inline] #[inline]
pub fn new(data: &[T]) -> Result<Self, SizeError> { pub fn new(data: &[T]) -> Result<Self, LengthError> {
let mut buf: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut buf = [const { MaybeUninit::<T>::uninit() };N];
let len = data.len(); let len = data.len();
if len > N { return Err(SizeError { cap: N, len }) }; if len > N { return Err(LengthError { capacity: N, len }) };
for (item, value) in buf.iter_mut().zip(data.iter()) { for (item, value) in buf.iter_mut().zip(data.iter()) {
item.write(value.clone()); item.write(value.clone());

View file

@ -1,25 +1,25 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use librum::SizedSlice; use oct::SizedSlice;
use std::vec::Vec; use std::vec::Vec;
#[test] #[test]

View file

@ -1,22 +1,22 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::SizedStr; use crate::SizedStr;

View file

@ -1,49 +1,43 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::{ use crate::SizedStr;
Decode, use crate::decode::{Decode, DecodeBorrowed, Input};
DecodeBorrowed, use crate::encode::{Encode, Output, SizedEncode};
Encode, use crate::error::{CollectionDecodeError, LengthError, StringError, Utf8Error};
IStream,
OStream,
SizedEncode,
SizedStr
};
use crate::error::{CollectionDecodeError, SizeError, StringError, Utf8Error};
impl<const N: usize> Decode for SizedStr<N> { impl<const N: usize> Decode for SizedStr<N> {
type Error = CollectionDecodeError<SizeError, Utf8Error>; type Error = CollectionDecodeError<LengthError, Utf8Error>;
#[inline] #[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> { fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap(); let len = Decode::decode(input).unwrap();
let data = stream.read(len); let data = input.read(len).unwrap();
Self::from_utf8(data) Self::from_utf8(data)
.map_err(|e| match e { .map_err(|e| match e {
StringError::BadUtf8(e) => CollectionDecodeError::Item(e), StringError::BadUtf8(e) => CollectionDecodeError::BadItem(e),
StringError::SmallBuffer(e) => CollectionDecodeError::Length(e), StringError::SmallBuffer(e) => CollectionDecodeError::BadLength(e),
_ => unreachable!(), _ => unreachable!(),
}) })
@ -56,8 +50,8 @@ impl<const N: usize> Encode for SizedStr<N> {
type Error = <str as Encode>::Error; type Error = <str as Encode>::Error;
#[inline(always)] #[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> { fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_str().encode(stream) self.as_str().encode(output)
} }
} }

View file

@ -1,26 +1,26 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use crate::{SizedSlice, SizedStr}; use crate::{SizedSlice, SizedStr};
use crate::error::{SizeError, StringError, Utf8Error}; use crate::error::{LengthError, StringError, Utf8Error};
use core::borrow::{Borrow, BorrowMut}; use core::borrow::{Borrow, BorrowMut};
use core::mem::{ManuallyDrop, MaybeUninit}; use core::mem::{ManuallyDrop, MaybeUninit};
@ -54,15 +54,15 @@ impl<const N: usize> SizedStr<N> {
/// ///
/// Each byte value must be a valid UTF-8 code point. /// Each byte value must be a valid UTF-8 code point.
#[inline] #[inline]
pub const fn from_utf8(data: &[u8]) -> Result<Self, StringError> { pub const fn from_utf8(s: &[u8]) -> Result<Self, StringError> {
if data.len() > N { return Err(StringError::SmallBuffer(SizeError { cap: N, len: data.len() })) }; if s.len() > N { return Err(StringError::SmallBuffer(LengthError { capacity: N, len: s.len() })) };
let s = match str::from_utf8(data) { let s = match str::from_utf8(s) {
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
let i = e.valid_up_to(); let i = e.valid_up_to();
let c = data[i]; let c = s[i];
return Err(StringError::BadUtf8(Utf8Error { value: c, index: i })); return Err(StringError::BadUtf8(Utf8Error { value: c, index: i }));
} }
@ -295,7 +295,7 @@ impl<const N: usize> FromStr for SizedStr<N> {
#[inline] #[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() > N { return Err(StringError::SmallBuffer(SizeError { cap: N, len: s.len() })) }; if s.len() > N { return Err(StringError::SmallBuffer(LengthError { capacity: N, len: s.len() })) };
let this = unsafe { Self::from_utf8_unchecked(s.as_bytes()) }; let this = unsafe { Self::from_utf8_unchecked(s.as_bytes()) };
Ok(this) Ok(this)

View file

@ -1,29 +1,29 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::SizedSlice; use crate::SizedSlice;
use crate::error::{SizeError, StringError}; use crate::error::{LengthError, StringError};
use core::fmt::{self, Debug, Display, Formatter}; use core::fmt::{self, Debug, Display, Formatter};
use core::hash::{Hash, Hasher}; use core::hash::{Hash, Hasher};
@ -34,12 +34,12 @@ use core::str::{Chars, CharIndices};
// Comparison facilities: // Comparison facilities:
mod cmp; mod cmp;
// Encode/decode facilities:
mod code;
// Conversion facilities: // Conversion facilities:
mod conv; mod conv;
// Encode/decode facilities:
mod serdes;
/// Stack-allocated string with maximum length. /// Stack-allocated string with maximum length.
/// ///
/// This is in contrast to [`String`](alloc::string::String) -- which has no size limit in practice -- and [`prim@str`], which is unsized. /// This is in contrast to [`String`](alloc::string::String) -- which has no size limit in practice -- and [`prim@str`], which is unsized.
@ -56,7 +56,7 @@ mod serdes;
/// Therefore, the following four strings have -- despite their different contents -- the same total size. /// Therefore, the following four strings have -- despite their different contents -- the same total size.
/// ///
/// ``` /// ```
/// use librum::SizedStr; /// use oct::SizedStr;
/// use std::str::FromStr; /// use std::str::FromStr;
/// ///
/// let str0 = SizedStr::<0x40>::default(); // Empty string. /// let str0 = SizedStr::<0x40>::default(); // Empty string.
@ -86,7 +86,7 @@ impl<const N: usize> SizedStr<N> {
/// If the internal buffer cannot contain the entirety of `s`, then an error is returned. /// If the internal buffer cannot contain the entirety of `s`, then an error is returned.
#[inline(always)] #[inline(always)]
pub const fn new(s: &str) -> Result<Self, StringError> { pub const fn new(s: &str) -> Result<Self, StringError> {
if s.len() > N { return Err(StringError::SmallBuffer(SizeError { cap: N, len: s.len() })) }; if s.len() > N { return Err(StringError::SmallBuffer(LengthError { capacity: N, len: s.len() })) };
let this = unsafe { Self::from_utf8_unchecked(s.as_bytes()) }; let this = unsafe { Self::from_utf8_unchecked(s.as_bytes()) };
Ok(this) Ok(this)
@ -201,4 +201,3 @@ impl<I: SliceIndex<str>, const N: usize> IndexMut<I> for SizedStr<N> {
self.get_mut(index).unwrap() self.get_mut(index).unwrap()
} }
} }

View file

@ -1,26 +1,26 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use librum::SizedStr; use oct::SizedStr;
use librum::error::{StringError, Utf8Error}; use oct::error::{StringError, Utf8Error};
use std::cmp::Ordering; use std::cmp::Ordering;
#[test] #[test]

View file

@ -1,34 +1,29 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::{ use crate::decode::{Decode, Input};
Decode, use crate::encode::{Encode, Output, SizedEncode};
Encode,
IStream,
OStream,
SizedEncode,
};
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::vec; use alloc::vec;
@ -39,7 +34,7 @@ use core::ops::{Deref, DerefMut, Index, IndexMut};
use core::ptr::{self, copy_nonoverlapping}; use core::ptr::{self, copy_nonoverlapping};
use core::slice::{self, SliceIndex}; use core::slice::{self, SliceIndex};
/// Typed encode buffer. /// Typed encode/decode slot.
/// ///
/// This structure is intended as a lightweight byte buffer suitable for encoding a single, predefined type. /// This structure is intended as a lightweight byte buffer suitable for encoding a single, predefined type.
/// ///
@ -48,16 +43,11 @@ use core::slice::{self, SliceIndex};
/// ///
/// # Examples /// # Examples
/// ///
/// Create a buffer for holding a `Request` enumeration: /// Create a slot for holding a `Request` enumeration:
/// ///
/// ``` /// ```
/// use librum::{ /// use oct::{SizedStr, Slot};
/// Buf, /// use oct::encode::{Encode, Output, SizedEncode};
/// Encode,
/// OStream,
/// SizedEncode,
/// SizedStr,
/// };
/// ///
/// #[derive(Debug, Encode, SizedEncode)] /// #[derive(Debug, Encode, SizedEncode)]
/// enum Request { /// enum Request {
@ -68,15 +58,15 @@ use core::slice::{self, SliceIndex};
/// SendMessage { message: SizedStr<0x80> }, /// SendMessage { message: SizedStr<0x80> },
/// } /// }
/// ///
/// let mut buf = Buf::new(); /// let mut buf = Slot::new();
/// ///
/// buf.write(Request::Join { username: "epsiloneridani".parse().unwrap() }).unwrap(); /// buf.write(Request::Join { username: "epsiloneridani".parse().unwrap() }).unwrap();
/// assert_eq!(buf.as_slice(), b"\0\0\x0E\0epsiloneridani"); /// assert_eq!(buf.as_slice(), b"\0\0\x0E\0epsiloneridani");
/// ///
/// // Do something with the buffer... /// // Do something with the slot...
/// ``` /// ```
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
pub struct Buf<T> { pub struct Slot<T> {
buf: Box<[u8]>, buf: Box<[u8]>,
len: usize, len: usize,
@ -84,8 +74,8 @@ pub struct Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> Buf<T> { impl<T> Slot<T> {
/// Allocates a new buffer suitable for encoding. /// Allocates a new slot suitable for encodings.
/// ///
/// The given capacity should be large enough to hold any expected encoding of `T`. /// The given capacity should be large enough to hold any expected encoding of `T`.
/// ///
@ -103,7 +93,7 @@ impl<T> Buf<T> {
} }
} }
/// Constructs a new buffer from raw parts. /// Constructs a new slot from raw parts.
/// ///
/// # Safety /// # Safety
/// ///
@ -126,7 +116,7 @@ impl<T> Buf<T> {
} }
} }
/// Gets a pointer to the first byte of the buffer. /// Gets a pointer to the first byte of the slot's buffer.
/// ///
/// Note that the all reads to bytes up to the amount specified by [`capacity`](Self::capacity) are valid (i.e. the bytes are always initialised). /// Note that the all reads to bytes up to the amount specified by [`capacity`](Self::capacity) are valid (i.e. the bytes are always initialised).
#[inline(always)] #[inline(always)]
@ -135,7 +125,7 @@ impl<T> Buf<T> {
self.buf.as_ptr() self.buf.as_ptr()
} }
/// Gets a mutable pointer to the first byte of the buffer. /// Gets a mutable pointer to the first byte of the slot's buffer.
/// ///
/// Note that the all reads to bytes up to the amount specified by [`capacity`](Self::capacity) are valid (i.e. the bytes are always initialised). /// Note that the all reads to bytes up to the amount specified by [`capacity`](Self::capacity) are valid (i.e. the bytes are always initialised).
#[inline(always)] #[inline(always)]
@ -144,10 +134,10 @@ impl<T> Buf<T> {
self.buf.as_mut_ptr() self.buf.as_mut_ptr()
} }
/// Gets a slice of the buffer. /// Gets a slice of the slot's buffer.
/// ///
/// The returned slice will only include the used part of the buffer (as specified by [`len`](Self::len)). /// The returned slice will only include the used part of the slot (as specified by [`len`](Self::len)).
/// This is in contrast to [`as_mut_slice`](Self::as_mut_slice), which references the entire buffer. /// This is in contrast to [`as_mut_slice`](Self::as_mut_slice), which references the entire slot buffer.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn as_slice(&self) -> &[u8] { pub fn as_slice(&self) -> &[u8] {
@ -155,9 +145,9 @@ impl<T> Buf<T> {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len()) } unsafe { slice::from_raw_parts(self.as_ptr(), self.len()) }
} }
/// Gets a mutable slice of the buffer. /// Gets a mutable slice of the slot's buffer.
/// ///
/// Contrary to [`as_slice`](Self::as_slice), this method returns a slice of the **entire** buffer (as specified by [`capacity`](Self::capacity)). /// Contrary to [`as_slice`](Self::as_slice), this method returns a slice of the slot's **entire** buffer (as specified by [`capacity`](Self::capacity)).
/// ///
/// Users should call [`set_len`](Self::set_len) if writing has modified the portion of used bytes. /// Users should call [`set_len`](Self::set_len) if writing has modified the portion of used bytes.
#[inline(always)] #[inline(always)]
@ -167,7 +157,7 @@ impl<T> Buf<T> {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.capacity()) } unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.capacity()) }
} }
/// Copies data from another slice. /// Copies data from a slice.
/// ///
/// The length of `self` is updated to reflect the new data. /// The length of `self` is updated to reflect the new data.
/// ///
@ -176,7 +166,7 @@ impl<T> Buf<T> {
pub fn copy_from_slice(&mut self, data: &[u8]) { pub fn copy_from_slice(&mut self, data: &[u8]) {
let len = data.len(); let len = data.len();
assert!(len <= self.capacity(), "buffer cannot contain source slice"); assert!(len <= self.capacity(), "slot cannot contain source slice");
unsafe { unsafe {
let src = data.as_ptr(); let src = data.as_ptr();
@ -192,44 +182,44 @@ impl<T> Buf<T> {
} }
} }
/// Sets the length of the buffer. /// Sets the length of the slot.
/// ///
/// The provided size is checked before being written (i.e. `len` may not be greater than [`len`](Self::len)). /// The provided size is checked before being written (i.e. `len` may not be greater than [`len`](Self::len)).
/// For the same operation *without* these checks, see [`set_len_unchecked`](Self::set_len_unchecked). /// For the same operation *without* these checks, see [`set_len_unchecked`](Self::set_len_unchecked).
/// ///
/// # Panics /// # Panics
/// ///
/// The provided size must not be greater than the buffer's capacity. /// The provided size must not be greater than the slot's capacity.
/// If this is the case, however, this method will panic. /// If this is the case, however, this method will panic.
#[inline(always)] #[inline(always)]
pub fn set_len(&mut self, len: usize) { pub fn set_len(&mut self, len: usize) {
assert!(len <= self.capacity(), "cannot extend buffer beyond capacity"); assert!(len <= self.capacity(), "cannot extend slot beyond capacity");
// SAFETY: The length has been tested. // SAFETY: The length has been tested.
unsafe { self.set_len_unchecked(len) } unsafe { self.set_len_unchecked(len) }
} }
/// Sets the length of the buffer without checks. /// Sets the length of the slot without checks.
/// ///
/// The provided size is **not** tested before being written. /// The provided size is **not** tested before being written.
/// For the same operation *with* checks, see [`set_len`](Self::set_len). /// For the same operation *with* checks, see [`set_len`](Self::set_len).
/// ///
/// # Safety /// # Safety
/// ///
/// The value of `len` may never be greater than the capacity of the buffer. /// The value of `len` may never be greater than the capacity of the slot.
/// Exceeding this will yield undefined behaviour. /// Exceeding this will yield undefined behaviour.
#[inline(always)] #[inline(always)]
pub unsafe fn set_len_unchecked(&mut self, len: usize) { pub unsafe fn set_len_unchecked(&mut self, len: usize) {
debug_assert!(len <= self.capacity(), "cannot extend buffer beyond capacity"); debug_assert!(len <= self.capacity(), "cannot extend slot beyond capacity");
// SAFETY: The length has been guaranteed by the // SAFETY: The length has been guaranteed by the
// caller. // caller.
self.len = len; self.len = len;
} }
/// Retrieves the capacity of the buffer. /// Retrieves the capacity of the slot.
/// ///
/// If the buffer was constructed using [`new`](Self::new), this value is exactly equal to that of [`MAX_ENCODED_SIZE`](SizedEncode::MAX_ENCODED_SIZE). /// If the slot was constructed using [`new`](Self::new), this value is exactly equal to [`MAX_ENCODED_SIZE`](SizedEncode::MAX_ENCODED_SIZE).
/// In other cases, however, this may either be greater or less than this value. /// In other cases, however, this may either be greater or less than this value.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
@ -237,18 +227,18 @@ impl<T> Buf<T> {
self.buf.len() self.buf.len()
} }
/// Retrieves the length of the buffer. /// Retrieves the length of the slot.
/// ///
/// This value specifically denotes the length of the previous encoding (if any). /// This value specifically denotes the length of the previous encoding (if any).
/// ///
/// For retrieving the capacity of the buffer, see [`capacity`](Self::capacity). /// For retrieving the capacity of the slot, see [`capacity`](Self::capacity).
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.len self.len
} }
/// Tests if the buffer is empty. /// Tests if the slot is empty.
/// ///
/// This is strictly equivalent to testing if [`len`](Self::len) is null. /// This is strictly equivalent to testing if [`len`](Self::len) is null.
#[inline(always)] #[inline(always)]
@ -257,7 +247,7 @@ impl<T> Buf<T> {
self.len() == 0x0 self.len() == 0x0
} }
/// Tests if the buffer is full. /// Tests if the slot is full.
/// ///
/// This is strictly equivalent to testing if [`len`](Self::len) is equal to [`capacity`](Self::capacity). /// This is strictly equivalent to testing if [`len`](Self::len) is equal to [`capacity`](Self::capacity).
#[inline(always)] #[inline(always)]
@ -268,8 +258,8 @@ impl<T> Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T: Encode> Buf<T> { impl<T: Encode> Slot<T> {
/// Encodes an object into the buffer. /// Encodes an object into the slot.
/// ///
/// The object is encoded as by being passed to <code>&lt;T as [Encode]&gt;::[encode](Encode::encode)</code>. /// The object is encoded as by being passed to <code>&lt;T as [Encode]&gt;::[encode](Encode::encode)</code>.
/// ///
@ -278,11 +268,11 @@ impl<T: Encode> Buf<T> {
/// Any error that occurs during encoding is passed on and returned from this method. /// Any error that occurs during encoding is passed on and returned from this method.
#[inline] #[inline]
pub fn write<U: Borrow<T>>(&mut self, value: U) -> Result<(), T::Error> { pub fn write<U: Borrow<T>>(&mut self, value: U) -> Result<(), T::Error> {
let mut stream = OStream::new(&mut self.buf); let mut stream = Output::new(&mut self.buf);
value.borrow().encode(&mut stream)?; value.borrow().encode(&mut stream)?;
let len = stream.close(); let len = stream.position();
self.set_len(len); self.set_len(len);
Ok(()) Ok(())
@ -290,8 +280,8 @@ impl<T: Encode> Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T: Decode> Buf<T> { impl<T: Decode> Slot<T> {
/// Decodes an object from the buffer. /// Decodes an object from the slot.
/// ///
/// This is done as by passing the contained bytes to <code>&lt;T as [Decode]&gt;::[decode](Decode::decode)</code>. /// This is done as by passing the contained bytes to <code>&lt;T as [Decode]&gt;::[decode](Decode::decode)</code>.
/// ///
@ -303,10 +293,10 @@ impl<T: Decode> Buf<T> {
/// Any error that occurs during decoding is passed on and returned from this method. /// Any error that occurs during decoding is passed on and returned from this method.
#[inline] #[inline]
pub fn read(&self) -> Result<T, T::Error> { pub fn read(&self) -> Result<T, T::Error> {
// We should only pass the used part of the buffer // We should only pass the used part of the slot to
// to `deserialise`. // `decode`.
let mut stream = IStream::new(&self.buf); let mut stream = Input::new(&self.buf);
let value = Decode::decode(&mut stream)?; let value = Decode::decode(&mut stream)?;
Ok(value) Ok(value)
@ -314,10 +304,10 @@ impl<T: Decode> Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T: SizedEncode> Buf<T> { impl<T: SizedEncode> Slot<T> {
/// Allocates a new buffer suitable for encoding. /// Allocates a new slot suitable for encoding.
/// ///
/// The capacity of the buffer is set so that any encoding of `T` may be stored (as specified by [`MAX_ENCODED_SIZE`](SizedEncode::MAX_ENCODED_SIZE)). /// The capacity of the slot is set so that any encoding of `T` may be stored (as specified by [`MAX_ENCODED_SIZE`](SizedEncode::MAX_ENCODED_SIZE)).
/// See also the [`with_capacity`](Self::with_capacity) constructor. /// See also the [`with_capacity`](Self::with_capacity) constructor.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
@ -328,7 +318,7 @@ impl<T: SizedEncode> Buf<T> {
/// See also [`as_mut_slice`](Self::as_mut_slice). /// See also [`as_mut_slice`](Self::as_mut_slice).
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> AsMut<[u8]> for Buf<T> { impl<T> AsMut<[u8]> for Slot<T> {
#[inline(always)] #[inline(always)]
fn as_mut(&mut self) -> &mut [u8] { fn as_mut(&mut self) -> &mut [u8] {
self.as_mut_slice() self.as_mut_slice()
@ -337,7 +327,7 @@ impl<T> AsMut<[u8]> for Buf<T> {
/// See also [`as_slice`](Self::as_slice). /// See also [`as_slice`](Self::as_slice).
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> AsRef<[u8]> for Buf<T> { impl<T> AsRef<[u8]> for Slot<T> {
#[inline(always)] #[inline(always)]
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
self.as_slice() self.as_slice()
@ -346,7 +336,7 @@ impl<T> AsRef<[u8]> for Buf<T> {
/// See also [`as_slice`](Self::as_slice). /// See also [`as_slice`](Self::as_slice).
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> Borrow<[u8]> for Buf<T> { impl<T> Borrow<[u8]> for Slot<T> {
#[inline(always)] #[inline(always)]
fn borrow(&self) -> &[u8] { fn borrow(&self) -> &[u8] {
self.as_slice() self.as_slice()
@ -355,7 +345,7 @@ impl<T> Borrow<[u8]> for Buf<T> {
/// See also [`as_mut_slice`](Self::as_mut_slice). /// See also [`as_mut_slice`](Self::as_mut_slice).
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> BorrowMut<[u8]> for Buf<T> { impl<T> BorrowMut<[u8]> for Slot<T> {
#[inline(always)] #[inline(always)]
fn borrow_mut(&mut self) -> &mut [u8] { fn borrow_mut(&mut self) -> &mut [u8] {
self.as_mut_slice() self.as_mut_slice()
@ -363,13 +353,13 @@ impl<T> BorrowMut<[u8]> for Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> Debug for Buf<T> { impl<T> Debug for Slot<T> {
#[inline(always)] #[inline(always)]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{:?}", self.as_slice()) } fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{:?}", self.as_slice()) }
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T: SizedEncode> Default for Buf<T> { impl<T: SizedEncode> Default for Slot<T> {
#[inline(always)] #[inline(always)]
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
@ -377,7 +367,7 @@ impl<T: SizedEncode> Default for Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> Deref for Buf<T> { impl<T> Deref for Slot<T> {
type Target = [u8]; type Target = [u8];
#[inline(always)] #[inline(always)]
@ -387,7 +377,7 @@ impl<T> Deref for Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> DerefMut for Buf<T> { impl<T> DerefMut for Slot<T> {
#[inline(always)] #[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice() self.as_mut_slice()
@ -395,7 +385,7 @@ impl<T> DerefMut for Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T, I: SliceIndex<[u8]>> Index<I> for Buf<T> { impl<T, I: SliceIndex<[u8]>> Index<I> for Slot<T> {
type Output = I::Output; type Output = I::Output;
#[inline(always)] #[inline(always)]
@ -405,7 +395,7 @@ impl<T, I: SliceIndex<[u8]>> Index<I> for Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T, I: SliceIndex<[u8]>> IndexMut<I> for Buf<T> { impl<T, I: SliceIndex<[u8]>> IndexMut<I> for Slot<T> {
#[inline(always)] #[inline(always)]
fn index_mut(&mut self, index: I) -> &mut Self::Output { fn index_mut(&mut self, index: I) -> &mut Self::Output {
self.get_mut(index).unwrap() self.get_mut(index).unwrap()
@ -413,7 +403,7 @@ impl<T, I: SliceIndex<[u8]>> IndexMut<I> for Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> PartialEq<[u8]> for Buf<T> { impl<T> PartialEq<[u8]> for Slot<T> {
#[inline(always)] #[inline(always)]
fn eq(&self, other: &[u8]) -> bool { fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other self.as_slice() == other
@ -421,7 +411,7 @@ impl<T> PartialEq<[u8]> for Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> PartialEq<&[u8]> for Buf<T> { impl<T> PartialEq<&[u8]> for Slot<T> {
#[inline(always)] #[inline(always)]
fn eq(&self, other: &&[u8]) -> bool { fn eq(&self, other: &&[u8]) -> bool {
self.as_slice() == *other self.as_slice() == *other
@ -429,7 +419,7 @@ impl<T> PartialEq<&[u8]> for Buf<T> {
} }
#[cfg_attr(doc, doc(cfg(feature = "alloc")))] #[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> PartialEq<&mut [u8]> for Buf<T> { impl<T> PartialEq<&mut [u8]> for Slot<T> {
#[inline(always)] #[inline(always)]
fn eq(&self, other: &&mut [u8]) -> bool { fn eq(&self, other: &&mut [u8]) -> bool {
self.as_slice() == *other self.as_slice() == *other

View file

@ -1,30 +1,30 @@
// Copyright 2024 Gabriel Bjørnager Jensen. // Copyright 2024 Gabriel Bjørnager Jensen.
// //
// This file is part of Librum. // This file is part of oct.
// //
// Librum is free software: you can redistribute it // oct is free software: you can redistribute it
// and/or modify it under the terms of the GNU // and/or modify it under the terms of the GNU
// Lesser General Public License as published by // Lesser General Public License as published by
// the Free Software Foundation, either version 3 // the Free Software Foundation, either version 3
// of the License, or (at your option) any later // of the License, or (at your option) any later
// version. // version.
// //
// Librum is distributed in the hope that it will // oct is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without // be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or // even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU // FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Less- // You should have received a copy of the GNU Less-
// er General Public License along with Librum. If // er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>. // not, see <https://www.gnu.org/licenses/>.
use librum::Buf; use oct::Slot;
use librum::error::CharDecodeError; use oct::error::CharDecodeError;
#[test] #[test]
fn test_buf_write_read() { fn test_buf_write_read() {
let mut buf = Buf::<char>::new(); let mut buf = Slot::<char>::new();
macro_rules! test_read { macro_rules! test_read {
($pattern:pat$(,)?) => {{ ($pattern:pat$(,)?) => {{