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
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.
## 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
* Update readme

View file

@ -1,13 +1,13 @@
[workspace]
members = ["librum", "librum-benchmarks", "librum-macros"]
members = ["oct", "oct-benchmarks", "oct-macros"]
resolver = "2"
[workspace.package]
authors = ["Gabriel Bjørnager Jensen"]
description = "Binary (de)serialiser."
readme = "README.md"
homepage = "https://achernar.dk/index.php?p=bzipper"
repository = "https://mandelbrot.dk/librum/"
homepage = "https://docs.rs/oct/latest/oct/"
repository = "https://mandelbrot.dk/oct/"
license = "LGPL-3.0-or-later"
keywords = ["api", "encoding", "io", "network", "no-std"]
categories = ["encoding", "network-programming", "parsing"]
@ -35,6 +35,7 @@ empty_enum_variants_with_brackets = "warn"
empty_line_after_doc_comments = "warn"
empty_line_after_outer_attr = "warn"
empty_structs_with_brackets = "warn"
enum_glob_use = "forbid"
enum_variant_names = "allow"
equatable_if_let = "warn"
excessive_precision = "allow"
@ -52,7 +53,6 @@ from_iter_instead_of_collect = "warn"
future_not_send = "deny"
if_not_else = "warn"
if_then_some_else_none = "warn"
ignored_unit_patterns = "warn"
impl_trait_in_params = "warn"
implicit_clone = "warn"
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 *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.
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
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.
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:
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 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_u32` | 1.130 | 1.084 | 0.749 | 2.793 |
| `encode_u128` | 2.340 | 2.328 | 1.543 | 6.380 |
| `encode_u8` | 0.968 | 0.857 | 0.733 | 0.979 |
| `encode_u32` | 1.065 | 0.999 | 0.730 | 2.727 |
| `encode_u128` | 2.168 | 2.173 | 1.510 | 6.246 |
| `encode_struct_unit` | 0.000 | 0.000 | 0.000 | 0.000 |
| `encode_struct_unnamed` | 1.218 | 1.160 | 0.838 | 2.392 |
| `encode_struct_named` | 3.077 | 1.501 | 0.975 | 3.079 |
| `encode_enum_unit` | 0.260 | 0.310 | 0.000 | 0.303 |
| `decode_u8` | 1.116 | 1.106 | 1.110 | 1.102 |
| `decode_non_zero_u8` | 1.228 | 1.236 | 1.269 | 1.263 |
| **Total time** &#8594; | 11.373 | 9.672 | 7.291 | 18.284 |
| **Total deviation (p.c.)** &#8594; | +56 | +33 | ±0 | +150 |
| `encode_struct_unnamed` | 1.241 | 1.173 | 0.823 | 3.350 |
| `encode_struct_named` | 3.079 | 1.507 | 0.973 | 3.082 |
| `encode_enum_unit` | 0.246 | 0.297 | 0.000 | 0.295 |
| `decode_u8` | 0.942 | 0.962 | 0.922 | 0.923 |
| `decode_non_zero_u8` | 1.126 | 1.159 | 1.127 | 1.160 |
| `decode_bool` | 1.040 | 1.099 | 1.055 | 1.177 |
| **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/
[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.
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.
Do feel free to conduct your own tests of Librum.
Do feel free to conduct your own tests of oct.
## 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.
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.
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:
```rust
use librum::{Buf, Decode, Encode};
use oct::Slot;
use oct::decode::Decode;
use oct::encode::Encode;
#[derive(Debug, Decode, Encode, PartialEq)]
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,
};
let mut buf = Buf::with_capacity(0x100);
let mut buf = Slot::with_capacity(0x100);
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.
These streams are separated into two type: *O-streams* (output streams) and *i-streams* (input streams).
The `Buf` type can be used to handle these streams.
These streams are separated into two type: *output streams* and *input streams*.
The `Slot` type can be used to handle these streams.
### Encoding
To encode an object directly using the `Encode` trait, simply allocate a buffer for the encoding and wrap it in an `OStream` object:
To encode an object directly using the `Encode` trait, simply allocate a buffer for the encoding and wrap it in an `Output` object:
```rust
use librum::{Encode, OStream, SizedEncode};
use oct::encode::{Encode, Output, SizedEncode};
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();
@ -129,10 +130,10 @@ assert_eq!(buf, [0x16, 0x04, 0x00, 0x00].as_slice());
Streams can also be used to chain multiple objects together:
```rust
use librum::{Encode, OStream, SizedEncode};
use oct::encode::{Encode, Output, SizedEncode};
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
// `String` and `SizedStr` types are usually
@ -156,26 +157,26 @@ If the encoded type additionally implements `SizedEncode`, then the maximum size
### Decoding
Decoding works with a similar syntax to encoding.
To decode a byte array, simply call the `decode` method with an `IStream` object:
To decode a byte array, simply call the `decode` method with an `Input` object:
```rust
use librum::{Decode, IStream};
use oct::decode::{Decode, Input};
let data = [0x54, 0x45];
let mut stream = IStream::new(&data);
let mut stream = Input::new(&data);
assert_eq!(u16::decode(&mut stream).unwrap(), 0x4554);
// 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(), 0x45);
// Including as tuples:
stream = IStream::new(&data);
stream = Input::new(&data);
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:
```rust
use librum::{Buf, Encode, Decode, SizedEncode};
use oct::Slot;
use oct::decode::Decode;
use oct::encode::{Encode, SizedEncode};
use std::io;
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
use std::thread::spawn;
@ -221,8 +224,8 @@ enum Response {
struct Party {
pub socket: UdpSocket,
pub request_buf: Buf::<Request>,
pub response_buf: Buf::<Response>,
pub request_buf: Slot::<Request>,
pub response_buf: Slot::<Response>,
}
impl Party {
@ -232,8 +235,8 @@ impl Party {
let this = Self {
socket,
request_buf: Buf::new(),
response_buf: Buf::new(),
request_buf: Slot::new(),
response_buf: Slot::new(),
};
Ok(this)
@ -286,28 +289,28 @@ spawn(move || {
## 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`
* *`proc-macro`: Pulls the procedural macros from the `librum-macros` crate
* *`alloc`: Enables the `Slot` type and implementations for e.g. `Box` and `Arc`
* *`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`
Features marked with * are enabled by default.
## Documentation
Librum has its documentation written in-source for use by `rustdoc`.
See [Docs.rs](https://docs.rs/librum/latest/librum/) for an on-line, rendered instance.
oct has its documentation written in-source for use by `rustdoc`.
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.
The nightly toolchain is therefore required when rendering them.
## 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.
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

View file

@ -1,7 +1,17 @@
<svg height="72" width="72" xmlns="http://www.w3.org/2000/svg">
<mask id="z">
<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" />
<svg height="96" width="96" xmlns="http://www.w3.org/2000/svg">
<mask id="tHorizontalArm">
<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>
<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>

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]
name = "librum-benchmarks"
version = "0.13.1"
name = "oct-benchmarks"
version = "0.14.0"
edition = "2021"
description = "Librum benchmarks."
description = "oct benchmarks."
authors.workspace = true
readme.workspace = true
@ -10,7 +10,7 @@ homepage.workspace = true
repository.workspace = true
[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"
rand = "0.8.0"

View file

@ -18,7 +18,7 @@ macro_rules! benchmark {
borsh: $borsh_op:block$(,)?
librum: $librum_op:block$(,)?
oct: $oct_op:block$(,)?
postcard: $postcard_op:block$(,)?
}$(,)?)+
@ -54,7 +54,7 @@ macro_rules! benchmark {
let mut total_bincode_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;
$({
@ -63,7 +63,7 @@ macro_rules! benchmark {
let mut bincode_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;
for i in 0x0..TEST_COUNT {
@ -73,7 +73,7 @@ macro_rules! benchmark {
bincode_duration += time! { $bincode_op };
borsh_duration += time! { $borsh_op };
librum_duration += time! { $librum_op };
oct_duration += time! { $oct_op };
postcard_duration += time! { $postcard_op };
eprint!("\u{001B}[000m");
@ -83,37 +83,37 @@ macro_rules! benchmark {
bincode_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);
eprint!("\u{001B}[000m");
eprintln!("bincode: {}", format_score(bincode_duration, librum_duration));
eprintln!("borsh: {}", format_score(borsh_duration, librum_duration));
eprintln!("librum: {}", format_score(librum_duration, librum_duration));
eprintln!("postcard: {}", format_score(postcard_duration, librum_duration));
eprintln!("bincode: {}", format_score(bincode_duration, oct_duration));
eprintln!("borsh: {}", format_score(borsh_duration, oct_duration));
eprintln!("oct: {}", format_score(oct_duration, oct_duration));
eprintln!("postcard: {}", format_score(postcard_duration, oct_duration));
total_bincode_duration += bincode_duration;
total_borsh_duration += borsh_duration;
total_librum_duration += librum_duration;
total_oct_duration += oct_duration;
total_postcard_duration += postcard_duration;
})*
eprintln!();
eprintln!("\u{001B}[001mtotal score:\u{001B}[022m");
eprintln!("bincode: {}", format_score(total_bincode_duration, total_librum_duration));
eprintln!("borsh: {}", format_score(total_borsh_duration, total_librum_duration));
eprintln!("librum: {}", format_score(total_librum_duration, total_librum_duration));
eprintln!("postcard: {}", format_score(total_postcard_duration, total_librum_duration));
eprintln!("bincode: {}", format_score(total_bincode_duration, total_oct_duration));
eprintln!("borsh: {}", format_score(total_borsh_duration, total_oct_duration));
eprintln!("oct: {}", format_score(total_oct_duration, total_oct_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(serde::Deserialize, serde::Serialize)]
#[repr(transparent)]
struct Unit;
#[derive(librum::Decode, librum::Encode, librum::SizedEncode)]
#[derive(oct::decode::Decode, oct::encode::Encode, oct::encode::SizedEncode)]
#[derive(borsh::BorshSerialize)]
#[derive(serde::Deserialize, serde::Serialize)]
#[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(serde::Deserialize, serde::Serialize)]
#[repr(transparent)]
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 {
#[inline(always)]
#[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>
where
T: Immutable + IntoBytes + Sized,
@ -180,15 +180,15 @@ where
}
fn main() {
println!("#####################");
println!("# LIBRUM BENCHMARKS #");
println!("#####################");
println!("##################");
println!("# OCT BENCHMARKS #");
println!("##################");
println!();
println!("Each benchmark has a version written for the following crates:");
println!();
println!("- Bincode: <https://crates.io/crates/bincode/>");
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!();
println!("The total time the benchmark took (including memory allocations and dealloca-");
@ -198,10 +198,10 @@ fn main() {
println!();
println!("When every benchmark has concluded, the total run time and vps is listed for");
println!("each crate. A percantage additionally compares the run time between the listed");
println!("crate and librum (which should always be c. `0%` for Librum itself). DO NOTE");
println!("THAT THESE FINAL RESULTS INDICATE A NON-WEIGHTED AVERAGE ACROSS BENCHMARKS. It");
println!("can therefore be skewed relative to real-world performance by the similarity of");
println!("some benchmarks.");
println!("crate and oct (which should always be c. `0%` for oct itself). DO NOTE THAT");
println!("THESE FINAL RESULTS INDICATE A NON-WEIGHTED AVERAGE ACROSS BENCHMARKS. It can");
println!("therefore be skewed relative to real-world performance by the similarity of some");
println!("benchmarks.");
println!();
eprintln!("test_count: {TEST_COUNT}");
@ -233,13 +233,13 @@ fn main() {
}
}
librum: {
use librum::{Encode, OStream, SizedEncode};
oct: {
use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = u8::MAX_ENCODED_SIZE;
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 {
random::<u8>().encode(&mut stream).unwrap();
@ -280,13 +280,13 @@ fn main() {
}
}
librum: {
use librum::{Encode, OStream, SizedEncode};
oct: {
use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = u32::MAX_ENCODED_SIZE;
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 {
random::<u32>().encode(&mut stream).unwrap();
@ -327,13 +327,13 @@ fn main() {
}
}
librum: {
use librum::{Encode, OStream, SizedEncode};
oct: {
use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = u128::MAX_ENCODED_SIZE;
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 {
random::<u128>().encode(&mut stream).unwrap();
@ -374,13 +374,13 @@ fn main() {
}
}
librum: {
use librum::{Encode, OStream, SizedEncode};
oct: {
use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = Unit::MAX_ENCODED_SIZE;
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 {
Unit.encode(&mut stream).unwrap();
@ -421,13 +421,13 @@ fn main() {
}
}
librum: {
use librum::{Encode, OStream, SizedEncode};
oct: {
use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = Unnamed::MAX_ENCODED_SIZE;
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 {
Unnamed::from_char(random()).encode(&mut stream).unwrap();
@ -468,13 +468,13 @@ fn main() {
}
}
librum: {
use librum::{Encode, OStream, SizedEncode};
oct: {
use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize = Named::MAX_ENCODED_SIZE;
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 {
Named::from_u64(random()).encode(&mut stream).unwrap();
@ -519,15 +519,15 @@ fn main() {
}
}
librum: {
use librum::{Encode, OStream, SizedEncode};
oct: {
use oct::encode::{Encode, Output, SizedEncode};
const ITEM_SIZE: usize =
isize::MAX_ENCODED_SIZE // discriminant
+ Unit::MAX_ENCODED_SIZE;
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 {
Enum::Unit(Unit).encode(&mut stream).unwrap();
@ -572,13 +572,14 @@ fn main() {
}
}
librum: {
use librum::{Decode, IStream, SizedEncode};
oct: {
use oct::decode::{Decode, Input};
use oct::encode::SizedEncode;
const ITEM_SIZE: usize = u8::MAX_ENCODED_SIZE;
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 {
let _ = u8::decode(&mut stream).unwrap();
@ -623,13 +624,14 @@ fn main() {
}
}
librum: {
use librum::{Decode, IStream, SizedEncode};
oct: {
use oct::decode::{Decode, Input};
use oct::encode::SizedEncode;
const ITEM_SIZE: usize = NonZero::<u8>::MAX_ENCODED_SIZE;
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 {
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]
name = "librum-macros"
version = "0.13.1"
name = "oct-macros"
version = "0.14.0"
edition = "2021"
documentation = "https://docs.rs/librum-macros/"
documentation = "https://docs.rs/oct-macros/"
authors.workspace = true
description.workspace = true

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use std::borrow::Borrow;

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use proc_macro2::TokenStream;
@ -82,14 +82,12 @@ impl Debug for GenericName {
impl ToTokens for GenericName {
#[inline(always)]
fn to_tokens(&self, tokens: &mut TokenStream) {
use GenericName::*;
match *self {
| Const(ref ident)
| Ty( ref ident)
| Self::Const(ref ident)
| Self::Ty( ref ident)
=> 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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::{GenericName, Repr};

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::{Discriminants, Repr};
@ -38,9 +38,9 @@ pub fn decode_enum(data: DataEnum, repr: Repr) -> TokenStream {
let commands = iter::repeat_n(
quote! {
::librum::Decode::decode(stream)
.map_err(::core::convert::Into::<::librum::error::GenericDecodeError>::into)
.map_err(::librum::error::EnumDecodeError::Field)?
::oct::decode::Decode::decode(stream)
.map_err(::core::convert::Into::<::oct::error::GenericDecodeError>::into)
.map_err(::oct::error::EnumDecodeError::BadField)?
},
variant.fields.len(),
);
@ -62,18 +62,18 @@ pub fn decode_enum(data: DataEnum, repr: Repr) -> TokenStream {
});
quote! {
type Error = ::librum::error::EnumDecodeError<#repr, ::librum::error::GenericDecodeError>;
type Error = ::oct::error::EnumDecodeError<#repr, ::oct::error::GenericDecodeError>;
#[inline]
fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result<Self, Self::Error> {
let discriminant = <#repr as ::librum::Decode>::decode(stream)
fn decode(stream: &mut ::oct::decode::Input) -> ::core::result::Result<Self, Self::Error> {
let discriminant = <#repr as ::oct::decode::Decode>::decode(stream)
.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 {
#(#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)

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use proc_macro2::TokenStream;
@ -28,8 +28,8 @@ use std::iter;
pub fn decode_struct(data: DataStruct) -> TokenStream {
let commands = iter::repeat_n(
quote! {
::librum::Decode::decode(stream)
.map_err(::core::convert::Into::<::librum::error::GenericDecodeError>::into)?
::oct::decode::Decode::decode(stream)
.map_err(::core::convert::Into::<::oct::error::GenericDecodeError>::into)?
},
data.fields.len(),
);
@ -50,10 +50,10 @@ pub fn decode_struct(data: DataStruct) -> TokenStream {
};
quote! {
type Error = ::librum::error::GenericDecodeError;
type Error = ::oct::error::GenericDecodeError;
#[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;
::core::result::Result::Ok(this)
}

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::{Discriminants, Repr};
@ -66,21 +66,21 @@ pub fn encode_enum(data: DataEnum, repr: Repr) -> TokenStream {
});
quote! {
type Error = ::librum::error::EnumEncodeError<#repr, ::librum::error::GenericEncodeError>;
type Error = ::oct::error::EnumEncodeError<#repr, ::oct::error::GenericEncodeError>;
#[allow(unreachable_patterns)]
#[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 {
#(
#patterns => {
<#repr as ::librum::Encode>::encode(&#discriminants, stream)
.map_err(::librum::error::EnumEncodeError::Discriminant)?;
<#repr as ::oct::encode::Encode>::encode(&#discriminants, stream)
.map_err(::oct::error::EnumEncodeError::BadDiscriminant)?;
#(
::librum::Encode::encode(#captures, stream)
.map_err(::core::convert::Into::<::librum::error::GenericEncodeError>::into)
.map_err(::librum::error::EnumEncodeError::Field)?;
::oct::encode::Encode::encode(#captures, stream)
.map_err(::core::convert::Into::<::oct::error::GenericEncodeError>::into)
.map_err(::oct::error::EnumEncodeError::BadField)?;
)*
}
)*

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use proc_macro2::{Span, TokenStream};
@ -48,15 +48,15 @@ pub fn encode_struct(data: DataStruct) -> TokenStream {
};
quote! {
type Error = ::librum::error::GenericEncodeError;
type Error = ::oct::error::GenericEncodeError;
#[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;
#(
::librum::Encode::encode(#captures, stream)
.map_err(::core::convert::Into::<::librum::error::GenericEncodeError>::into)?;
::oct::encode::Encode::encode(#captures, stream)
.map_err(::core::convert::Into::<::oct::error::GenericEncodeError>::into)?;
)*
::core::result::Result::Ok(())

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::use_mod;

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::Repr;
@ -48,7 +48,7 @@ pub fn sized_encode_enum(data: DataEnum, repr: Repr) -> TokenStream {
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 };
)*

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use proc_macro2::TokenStream;
@ -31,6 +31,6 @@ pub fn sized_encode_struct(data: DataStruct) -> TokenStream {
.collect();
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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// 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:
extern crate self as librum_macros;
extern crate self as oct_macros;
macro_rules! use_mod {
($vis:vis $name:ident) => {
@ -51,7 +51,7 @@ pub fn derive_decode(input: TokenStream) -> TokenStream {
let output = impl_derive_macro(
input,
parse2(quote! { ::librum::Decode }).unwrap(),
parse2(quote! { ::oct::decode::Decode }).unwrap(),
None,
impls::decode_struct,
impls::decode_enum,
@ -68,7 +68,7 @@ pub fn derive_encode(input: TokenStream) -> TokenStream {
let output = impl_derive_macro(
input,
parse2(quote! { ::librum::Encode }).unwrap(),
parse2(quote! { ::oct::encode::Encode }).unwrap(),
None,
impls::encode_struct,
impls::encode_enum,
@ -85,7 +85,7 @@ pub fn derive_sized_encode(input: TokenStream) -> TokenStream {
let output = impl_derive_macro(
input,
parse2(quote! { ::librum::SizedEncode }).unwrap(),
parse2(quote! { ::oct::encode::SizedEncode }).unwrap(),
None,
impls::sized_encode_struct,
impls::sized_encode_enum,

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use proc_macro2::{Span, TokenStream};
@ -61,22 +61,20 @@ impl Repr {
for attr in attrs {
if attr.path().is_ident("repr") {
attr.parse_nested_meta(|meta| {
use Repr::*;
let ident = meta.path.require_ident()?;
if ident == "u8" { this = Some(U8) }
else if ident == "i8" { this = Some(I8) }
else if ident == "u16" { this = Some(U16) }
else if ident == "i16" { this = Some(I16) }
else if ident == "u32" { this = Some(U32) }
else if ident == "i32" { this = Some(I32) }
else if ident == "u64" { this = Some(U64) }
else if ident == "i64" { this = Some(I64) }
else if ident == "u128" { this = Some(U128) }
else if ident == "i128" { this = Some(I128) }
else if ident == "usize" { this = Some(Usize) }
else if ident == "isize" { this = Some(Isize) }
if ident == "u8" { this = Some(Self::U8) }
else if ident == "i8" { this = Some(Self::I8) }
else if ident == "u16" { this = Some(Self::U16) }
else if ident == "i16" { this = Some(Self::I16) }
else if ident == "u32" { this = Some(Self::U32) }
else if ident == "i32" { this = Some(Self::I32) }
else if ident == "u64" { this = Some(Self::U64) }
else if ident == "i64" { this = Some(Self::I64) }
else if ident == "u128" { this = Some(Self::U128) }
else if ident == "i128" { this = Some(Self::I128) }
else if ident == "usize" { this = Some(Self::Usize) }
else if ident == "isize" { this = Some(Self::Isize) }
else { panic!("`{ident}` is not a derivable enumeration representation") };
Ok(())
@ -92,21 +90,19 @@ impl Repr {
#[inline]
#[must_use]
pub const fn to_str(self) -> &'static str {
use Repr::*;
match self {
U8 => "u8",
I8 => "i8",
U16 => "u16",
I16 => "i16",
U32 => "u32",
I32 => "i32",
U64 => "u64",
I64 => "i64",
U128 => "u128",
I128 => "i128",
Usize => "usize",
Isize => "isize",
Self::U8 => "u8",
Self::I8 => "i8",
Self::U16 => "u16",
Self::I16 => "i16",
Self::U32 => "u32",
Self::I32 => "i32",
Self::U64 => "u64",
Self::I64 => "i64",
Self::U128 => "u128",
Self::I128 => "i128",
Self::Usize => "usize",
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]
name = "librum"
version = "0.13.1"
name = "oct"
version = "0.14.0"
edition = "2021"
rust-version = "1.83"
documentation = "https://docs.rs/librum/"
documentation = "https://docs.rs/oct/"
authors.workspace = true
description.workspace = true
@ -21,11 +21,11 @@ all-features = true
default = ["alloc", "proc-macro", "std"]
alloc = []
proc-macro = ["librum-macros"]
proc-macro = ["oct-macros"]
std = []
[dependencies]
librum-macros = { path = "../librum-macros", version = "0.13.0", optional = true}
oct-macros = { path = "../oct-macros", version = "0.14.0", optional = true}
[lints]
workspace = true

View file

@ -1,30 +1,29 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
#[cfg(test)]
mod tests;
use crate::{DecodeBorrowed, IStream, SizedEncode};
use crate::decode::{DecodeBorrowed, Input};
use crate::error::{
BoolDecodeError,
CStringDecodeError,
CharDecodeError,
CollectionDecodeError,
@ -104,12 +103,12 @@ pub trait Decode: Sized {
/// The type returned in case of error.
type Error;
/// Decodes an object from the provided stream.
/// Decodes an object from the provided input.
///
/// # Errors
///
/// If decoding fails due to e.g. an invalid byte sequence in the stream, then an error should be returned.
fn decode(stream: &mut IStream) -> Result<Self, Self::Error>;
/// If decoding fails due to e.g. an invalid byte sequence in the input, then an error should be returned.
fn decode(input: &mut Input) -> Result<Self, Self::Error>;
}
/// Implemented for tuples with up to twelve members.
@ -118,9 +117,9 @@ impl<T: Decode> Decode for (T, ) {
type Error = T::Error;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let this = (Decode::decode(stream)?, );
Ok(this)
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let this = (Decode::decode(input)?, );
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>>;
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
// 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() {
let value = Decode::decode(stream)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?;
let value = Decode::decode(input)
.map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
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-
// served for the greedy rustc devs.
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;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(input)?;
let this = Self::new(value);
Ok(this)
Result::Ok(this)
}
}
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]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = u8::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(value) = u8::decode(input);
match value {
0x0 => Ok(false),
0x1 => Ok(true),
_ => Err(BoolDecodeError { value })
}
let this = value != 0x0;
Result::Ok(this)
}
}
@ -185,20 +184,20 @@ impl<T: Decode> Decode for Bound<T> {
type Error = EnumDecodeError<u8, T::Error>;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let discriminant = u8::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(discriminant) = u8::decode(input);
let this = match discriminant {
0x0 => {
let bound = Decode::decode(stream)
.map_err(EnumDecodeError::Field)?;
let bound = Decode::decode(input)
.map_err(EnumDecodeError::BadField)?;
Self::Included(bound)
}
0x1 => {
let bound = Decode::decode(stream)
.map_err(EnumDecodeError::Field)?;
let bound = Decode::decode(input)
.map_err(EnumDecodeError::BadField)?;
Self::Excluded(bound)
}
@ -208,7 +207,7 @@ impl<T: Decode> Decode for Bound<T> {
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;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(input)?;
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;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(input)?;
let this = Self::new(value);
Ok(this)
Result::Ok(this)
}
}
@ -242,14 +241,17 @@ impl Decode for char {
type Error = CharDecodeError;
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let code_point = u32::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(code_point) = u32::decode(input);
let this = code_point
.try_into()
.map_err(|_| CharDecodeError { code_point })?;
match code_point {
code_point @ (0x0000..=0xD7FF | 0xDE00..=0x10FFFF) => {
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;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(input)?;
let this = Self::Owned(value);
Ok(this)
Result::Ok(this)
}
}
@ -277,10 +279,10 @@ impl Decode for CString {
type Error = CStringDecodeError;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(len) = Decode::decode(input);
let data = stream.read(len);
let data = input.read(len).unwrap();
for (i, c) in data.iter().enumerate() {
if *c == b'\x00' { return Err(CStringDecodeError { index: i }) };
@ -298,7 +300,7 @@ impl Decode for CString {
// SAFETY: We have already tested the data.
let this = unsafe { Self::from_vec_unchecked(buf) };
Ok(this)
Result::Ok(this)
}
}
@ -306,12 +308,12 @@ impl Decode for Duration {
type Error = Infallible;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let secs = Decode::decode(stream)?;
let nanos = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(secs) = Decode::decode(input);
let Ok(nanos) = Decode::decode(input);
let this = Self::new(secs, nanos);
Ok(this)
Result::Ok(this)
}
}
@ -326,22 +328,22 @@ where
type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, E>>;
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(len) = Decode::decode(input);
let mut this = Self::with_capacity_and_hasher(len, Default::default());
for i in 0x0..len {
let key= Decode::decode(stream)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?;
let key= Decode::decode(input)
.map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
let value = Decode::decode(stream)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?;
let value = Decode::decode(input)
.map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
this.insert(key, value);
}
Ok(this)
Result::Ok(this)
}
}
@ -355,19 +357,19 @@ where
type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, K::Error>>;
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(len) = Decode::decode(input);
let mut this = Self::with_capacity_and_hasher(len, Default::default());
for i in 0x0..len {
let key = Decode::decode(stream)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }) )?;
let key = Decode::decode(input)
.map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }) )?;
this.insert(key);
}
Ok(this)
Result::Ok(this)
}
}
@ -375,7 +377,7 @@ impl Decode for Infallible {
type Error = Self;
#[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")
}
}
@ -384,18 +386,18 @@ impl Decode for IpAddr {
type Error = EnumDecodeError<u8, Infallible>;
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let discriminant = u8::decode(stream)
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let discriminant = u8::decode(input)
.map_err(EnumDecodeError::InvalidDiscriminant)?;
let this = match discriminant {
0x4 => Self::V4(Decode::decode(stream).unwrap()),
0x6 => Self::V6(Decode::decode(stream).unwrap()),
0x4 => Self::V4(Decode::decode(input).unwrap()),
0x6 => Self::V6(Decode::decode(input).unwrap()),
value => return Err(EnumDecodeError::UnassignedDiscriminant { value })
};
Ok(this)
Result::Ok(this)
}
}
@ -403,9 +405,11 @@ impl Decode for Ipv4Addr {
type Error = Infallible;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?;
Ok(Self::from_bits(value))
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(value) = Decode::decode(input);
let this = Self::from_bits(value);
Result::Ok(this)
}
}
@ -413,9 +417,11 @@ impl Decode for Ipv6Addr {
type Error = Infallible;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?;
Ok(Self::from_bits(value))
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(value) = Decode::decode(input);
let this = Self::from_bits(value);
Result::Ok(this)
}
}
@ -423,9 +429,10 @@ impl Decode for isize {
type Error = Infallible;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = i16::decode(stream)?;
Ok(value as Self)
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(value) = i16::decode(input);
Result::Ok(value as Self)
}
}
@ -435,19 +442,19 @@ impl<T: Decode> Decode for LinkedList<T> {
type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, T::Error>>;
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let len = usize::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(len) = usize::decode(input);
let mut this = Self::new();
for i in 0x0..len {
let value = T::decode(stream)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?;
let value = T::decode(input)
.map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
this.push_back(value);
}
Ok(this)
Result::Ok(this)
}
}
@ -457,8 +464,11 @@ impl<T: Decode> Decode for Mutex<T> {
type Error = T::Error;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
Ok(Self::new(Decode::decode(stream)?))
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
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)] // ???
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let sign = bool::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let sign = bool::decode(input)
.map_err::<T::Error, _>(|_e| unreachable!())?;
let this = if sign {
Some(Decode::decode(stream)?)
Some(Decode::decode(input)?)
} else {
None
};
Ok(this)
Result::Ok(this)
}
}
@ -484,8 +495,8 @@ impl<T> Decode for PhantomData<T> {
type Error = Infallible;
#[inline(always)]
fn decode(_stream: &mut IStream) -> Result<Self, Self::Error> {
Ok(Self)
fn decode(_input: &mut Input) -> Result<Self, Self::Error> {
Result::Ok(Self)
}
}
@ -493,8 +504,8 @@ impl Decode for PhantomPinned {
type Error = Infallible;
#[inline(always)]
fn decode(_stream: &mut IStream) -> Result<Self, Self::Error> {
Ok(Self)
fn decode(_input: &mut Input) -> Result<Self, Self::Error> {
Result::Ok(Self)
}
}
@ -502,11 +513,11 @@ impl<T: Decode> Decode for Range<T> {
type Error = T::Error;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let start = Decode::decode(stream)?;
let end = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let start = Decode::decode(input)?;
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;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let start = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let start = Decode::decode(input)?;
Ok(start..)
Result::Ok(start..)
}
}
@ -525,8 +536,8 @@ impl Decode for RangeFull {
type Error = Infallible;
#[inline(always)]
fn decode(_stream: &mut IStream) -> Result<Self, Self::Error> {
Ok(..)
fn decode(_input: &mut Input) -> Result<Self, Self::Error> {
Result::Ok(..)
}
}
@ -534,11 +545,11 @@ impl<T: Decode> Decode for RangeInclusive<T> {
type Error = T::Error;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let start = Decode::decode(stream)?;
let end = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let start = Decode::decode(input)?;
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;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let end = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
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;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let end = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
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;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
Ok(Self::new(Decode::decode(stream)?))
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
Result::Ok(Self::new(Decode::decode(input)?))
}
}
@ -579,15 +590,15 @@ impl<T: Decode> Decode for RefCell<T> {
type Error = T::Error;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(input)?;
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
T: Decode<Error = Err>,
E: Decode<Error = Err>,
@ -595,23 +606,23 @@ where
type Error = EnumDecodeError<bool, Err>;
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let sign = bool::decode(stream)
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let sign = bool::decode(input)
.map_err(EnumDecodeError::InvalidDiscriminant)?;
let this = if sign {
let value = Decode::decode(stream)
.map_err(EnumDecodeError::Field)?;
let value = Decode::decode(input)
.map_err(EnumDecodeError::BadField)?;
Err(value)
} else {
let value = Decode::decode(stream)
.map_err(EnumDecodeError::Field)?;
let value = Decode::decode(input)
.map_err(EnumDecodeError::BadField)?;
Ok(value)
};
Ok(this)
Result::Ok(this)
}
}
@ -621,11 +632,11 @@ impl<T: Decode> Decode for RwLock<T> {
type Error = T::Error;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(input)?;
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;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(input)?;
let this = Self(value);
Ok(this)
Result::Ok(this)
}
}
@ -645,17 +656,15 @@ impl Decode for SocketAddr {
type Error = EnumDecodeError<u8, Infallible>;
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let discriminant = u8::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(discriminant) = u8::decode(input);
let this = match discriminant {
0x4 => Self::V4(Decode::decode(stream).unwrap()),
0x6 => Self::V6(Decode::decode(stream).unwrap()),
match discriminant {
0x4 => Result::Ok(Self::V4(Decode::decode(input).unwrap())),
0x6 => Result::Ok(Self::V6(Decode::decode(input).unwrap())),
value => return Err(EnumDecodeError::UnassignedDiscriminant { value })
};
Ok(this)
value => Err(EnumDecodeError::UnassignedDiscriminant { value }),
}
}
}
@ -663,12 +672,12 @@ impl Decode for SocketAddrV4 {
type Error = Infallible;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let ip = Decode::decode(stream)?;
let port = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let ip = Decode::decode(input)?;
let port = Decode::decode(input)?;
let this = Self::new(ip, port);
Ok(this)
Result::Ok(this)
}
}
@ -676,14 +685,14 @@ impl Decode for SocketAddrV6 {
type Error = Infallible;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let ip = Decode::decode(stream)?;
let port = Decode::decode(stream)?;
let flow_info = Decode::decode(stream)?;
let scope_id = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let ip = Decode::decode(input)?;
let port = Decode::decode(input)?;
let flow_info = Decode::decode(input)?;
let scope_id = Decode::decode(input)?;
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>;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(len) = Decode::decode(input);
let data = stream.read(len);
let data = input.read(len).unwrap();
str::from_utf8(data)
.map_err(|e| {
let i = e.valid_up_to();
let c = data[i];
if let Err(e) = str::from_utf8(data) {
let i = e.valid_up_to();
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);
@ -718,7 +730,7 @@ impl Decode for String {
// SAFETY: We have already tested the raw data.
let this = unsafe { Self::from_utf8_unchecked(v) };
Ok(this)
Result::Ok(this)
}
}
@ -728,8 +740,8 @@ impl Decode for SystemTime {
type Error = SystemTimeDecodeError;
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let time = i64::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(time) = i64::decode(input);
let this = if time.is_positive() {
let time = time as u64;
@ -749,8 +761,8 @@ impl Decode for () {
type Error = Infallible;
#[inline(always)]
fn decode(_stream: &mut IStream) -> Result<Self, Self::Error> {
Ok(())
fn decode(_input: &mut Input) -> Result<Self, Self::Error> {
Result::Ok(())
}
}
@ -758,9 +770,9 @@ impl Decode for usize {
type Error = Infallible;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = u16::decode(stream)?;
Ok(value as Self)
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = u16::decode(input)?;
Result::Ok(value as Self)
}
}
@ -770,15 +782,15 @@ impl<T: Decode> Decode for Vec<T> {
type Error = CollectionDecodeError<Infallible, ItemDecodeError<usize, T::Error>>;
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let Ok(len) = Decode::decode(input);
let mut this = Self::with_capacity(len);
let buf = this.as_mut_ptr();
for i in 0x0..len {
let value = Decode::decode(stream)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?;
let value = Decode::decode(input)
.map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
// SAFETY: Each index is within bounds (i.e. capac-
// ity).
@ -788,7 +800,7 @@ impl<T: Decode> Decode for Vec<T> {
// SAFETY: We have initialised the buffer.
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;
#[inline(always)]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let value = Decode::decode(stream)?;
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let value = Decode::decode(input)?;
let this = Self(value);
Ok(this)
Result::Ok(this)
}
}
macro_rules! impl_numeric {
($ty:ty$(,)?) => {
impl ::librum::Decode for $ty {
impl ::oct::decode::Decode for $ty {
type Error = ::core::convert::Infallible;
#[inline]
fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result<Self, Self::Error> {
let mut data = [::core::default::Default::default(); Self::MAX_ENCODED_SIZE];
stream.read_into(&mut data);
fn decode(input: &mut ::oct::decode::Input) -> ::core::result::Result<Self, Self::Error> {
let mut data = [::core::default::Default::default(); <Self as ::oct::encode::SizedEncode>::MAX_ENCODED_SIZE];
input.read_into(&mut data).unwrap();
let this = Self::from_le_bytes(data);
Ok(this)
::core::result::Result::Ok(this)
}
}
};
@ -826,19 +838,19 @@ macro_rules! impl_tuple {
$($tys:ident),+$(,)?
} => {
#[doc(hidden)]
impl<$($tys, )* E> ::librum::Decode for ($($tys, )*)
impl<$($tys, )* E> ::oct::decode::Decode for ($($tys, )*)
where
$($tys: Decode<Error = E>, )*
{
type Error = E;
#[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 = (
$( <$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 {
($ty:ty$(,)?) => {
impl ::librum::Decode for ::core::num::NonZero<$ty> {
type Error = ::librum::error::NonZeroDecodeError;
impl ::oct::decode::Decode for ::core::num::NonZero<$ty> {
type Error = ::oct::error::NonZeroDecodeError;
#[inline]
fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result<Self, Self::Error> {
let Ok(value) = <$ty as ::librum::Decode>::decode(stream);
fn decode(input: &mut ::oct::decode::Input) -> ::core::result::Result<Self, Self::Error> {
use ::core::result::Result;
let this = ::core::num::NonZero::new(value)
.ok_or(::librum::error::NonZeroDecodeError)?;
let Result::Ok(value) = <$ty as ::oct::decode::Decode>::decode(input);
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_attr(doc, doc(cfg(target_has_atomic = $width)))]
impl ::librum::Decode for $atomic_ty {
type Error = <$ty as ::librum::Decode>::Error;
impl ::oct::decode::Decode for $atomic_ty {
type Error = <$ty as ::oct::decode::Decode>::Error;
#[inline(always)]
fn decode(stream: &mut ::librum::IStream) -> ::core::result::Result<Self, Self::Error> {
let value = ::librum::Decode::decode(stream)?;
fn decode(input: &mut ::oct::decode::Input) -> ::core::result::Result<Self, Self::Error> {
let value = ::oct::decode::Decode::decode(input)?;
let this = Self::new(value);
Ok(this)
::core::result::Result::Ok(this)
}
}
};

View file

@ -1,32 +1,33 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// 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::vec::Vec;
use std::string::String;
macro_rules! test {
($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 right = $value;
@ -101,6 +102,7 @@ fn test_decode_derive() {
Unnamed(i32),
Named { timestamp: u64 },
}
test!(ProcExit: [
0x01, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x0B, 0x5E,
0x00, 0x00, 0x00, 0x00,

View file

@ -1,25 +1,25 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::Decode;
use crate::decode::Decode;
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`.
///
/// 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).
///
/// # Arrays

View file

@ -19,16 +19,18 @@
// er General Public License along with Librum. If
// not, see <https://www.gnu.org/licenses/>.
use crate::error::InputError;
use core::ptr::copy_nonoverlapping;
use core::slice;
/// Byte stream suitable for input.
pub struct IStream<'a> {
/// Byte stream suitable for reading.
pub struct Input<'a> {
buf: &'a [u8],
pos: usize,
}
impl<'a> IStream<'a> {
impl<'a> Input<'a> {
/// Constructs a new i-stream.
#[inline(always)]
#[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.
#[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;
assert!(
remaining >= count,
"cannot read ({count}) bytes at ({}) from stream with capacity of ({})",
self.pos,
self.buf.len(),
);
if remaining < count {
return Err(InputError {
capacity: self.buf.len(),
position: self.pos,
count,
});
}
let data = unsafe {
let ptr = self.buf.as_ptr().add(self.pos);
@ -62,7 +65,7 @@ impl<'a> IStream<'a> {
self.pos += count;
data
Ok(data)
}
/// 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.
#[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 remaining = self.buf.len() - self.pos;
let remaining = self.remaining();
assert!(
remaining >= count,
"cannot read ({count}) bytes at ({}) from stream with capacity of ({})",
self.pos,
self.buf.len(),
);
if remaining < count {
return Err(InputError {
capacity: self.buf.len(),
position: self.pos,
count,
});
}
unsafe {
let src = self.buf.as_ptr().add(self.pos);
@ -92,15 +96,30 @@ impl<'a> IStream<'a> {
}
self.pos += count;
Ok(())
}
/// Closes the stream.
///
/// The total ammount of bytes read is returned.
/// Retrieves the maximum capacity of the input stream.
#[inline(always)]
pub const fn close(self) -> usize {
let Self { pos, .. } = self;
#[must_use]
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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
#[cfg(test)]
mod tests;
use crate::OStream;
use crate::encode::Output;
use crate::error::{
CollectionEncodeError,
EnumEncodeError,
@ -96,7 +96,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
/// It is recommended to simply derive this trait for custom types.
/// 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
///
@ -107,7 +107,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
/// // plementation is equivalent to what would have
/// // been derived.
///
/// use librum::{Encode, OStream};
/// use oct::encode::{Encode, Output};
/// use core::convert::Infallible;
///
/// struct Foo {
@ -120,13 +120,13 @@ use std::time::{SystemTime, UNIX_EPOCH};
///
/// 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.
///
/// self.bar.encode(stream)?;
/// self.baz.encode(stream)?;
/// self.bar.encode(output)?;
/// self.baz.encode(output)?;
///
/// Ok(())
/// Result::Ok(())
/// }
/// }
/// ```
@ -134,7 +134,7 @@ pub trait Encode {
/// The type returned in case of error.
type Error;
/// Encodes `self` into the provided stream.
/// Encodes `self` into the provided output.
///
/// # Errors
///
@ -142,16 +142,16 @@ pub trait Encode {
///
/// # Panics
///
/// If `stream` cannot contain the entirety of the resulting encoding, then this method should panic.
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error>;
/// If `output` cannot contain the entirety of the resulting encoding, then this method should panic.
fn encode(&self, output: &mut Output) -> Result<(), Self::Error>;
}
impl<T: Encode + ?Sized> Encode for &T {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
T::encode(self, stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, output)
}
}
@ -159,8 +159,8 @@ impl<T: Encode + ?Sized> Encode for &mut T {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
T::encode(self, stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, output)
}
}
@ -170,8 +170,8 @@ impl<T: Encode> Encode for (T, ) {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.0.encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
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>>;
/// 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)]
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() {
v
.encode(stream)
.map_err(|e| CollectionEncodeError::Item(ItemEncodeError { index: i, error: e }))?;
.encode(output)
.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.
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self
.len()
.encode(stream)
.map_err(CollectionEncodeError::Length)?;
.encode(output)
.map_err(CollectionEncodeError::BadLength)?;
for (i,v) in self.iter().enumerate() {
v
.encode(stream)
.map_err(|e| CollectionEncodeError::Item(ItemEncodeError { index: i, error: e }))?;
.encode(output)
.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;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
T::encode(self, stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, output)
}
}
impl Encode for bool {
type Error = <u8 as Encode>::Error;
/// Encodes the raw representationf of the boolean.
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
u8::from(*self).encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
u8::from(*self).encode(output)
}
}
@ -237,24 +239,24 @@ impl<T: Encode> Encode for Bound<T> {
type Error = EnumEncodeError<u8, T::Error>;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
match *self {
Self::Included(ref bound) => {
0x0u8.encode(stream).unwrap();
bound.encode(stream).map_err(EnumEncodeError::Field)?;
let Ok(_) = 0x0u8.encode(output);
bound.encode(output).map_err(EnumEncodeError::BadField)?;
}
Self::Excluded(ref bound) => {
0x1u8.encode(stream).unwrap();
bound.encode(stream).map_err(EnumEncodeError::Field)?;
let Ok(_) = 0x1u8.encode(output);
bound.encode(output).map_err(EnumEncodeError::BadField)?;
}
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;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
T::encode(self, stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, output)
}
}
@ -273,8 +275,8 @@ impl<T: Copy + Encode> Encode for Cell<T> {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.get().encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.get().encode(output)
}
}
@ -282,8 +284,8 @@ impl Encode for char {
type Error = <u32 as Encode>::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
u32::from(*self).encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
u32::from(*self).encode(output)
}
}
@ -293,8 +295,8 @@ impl<T: Encode + ?Sized + ToOwned> Encode for Cow<'_, T> {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
T::encode(self, stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
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.
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.to_bytes().encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.to_bytes().encode(output)
}
}
@ -315,8 +317,8 @@ impl Encode for CString {
/// See the the implementation of [`CStr`].
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.as_c_str().encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_c_str().encode(output)
}
}
@ -325,11 +327,11 @@ impl Encode for Duration {
/// Encodes the duration's seconds and nanoseconds counters sequentially.
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.as_secs().encode(stream).unwrap();
self.subsec_nanos().encode(stream).unwrap();
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_secs().encode(output)?;
self.subsec_nanos().encode(output)?;
Ok(())
Result::Ok(())
}
}
@ -344,13 +346,13 @@ where
type Error = E;
#[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 {
key.encode(stream)?;
value.encode(stream)?;
key.encode(output)?;
value.encode(output)?;
}
Ok(())
Result::Ok(())
}
}
@ -364,12 +366,12 @@ where
type Error = K::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
for key in self {
key.encode(stream)?;
key.encode(output)?;
}
Ok(())
Result::Ok(())
}
}
@ -379,9 +381,9 @@ impl Encode for Infallible {
type Error = Self;
#[inline(always)]
fn encode(&self, _stream: &mut OStream) -> Result<(), Self::Error> {
// SAFETY: `Infallible` can **never** be construct-
// ed.
fn encode(&self, _output: &mut Output) -> Result<(), Self::Error> {
// SAFETY: `Infallible` objects can never be con-
// structed
unsafe { unreachable_unchecked() }
}
}
@ -393,22 +395,22 @@ impl Encode for IpAddr {
///
/// See also the implementations of [`Ipv4Addr`] and [`Ipv6Addr`].
#[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.
match *self {
Self::V4(ref addr) => {
0x4u8.encode(stream).map_err(EnumEncodeError::Discriminant)?;
addr.encode(stream).map_err(EnumEncodeError::Field)?;
0x4u8.encode(output).map_err(EnumEncodeError::BadDiscriminant)?;
addr.encode(output).map_err(EnumEncodeError::BadField)?;
}
Self::V6(ref addr) => {
0x6u8.encode(stream).map_err(EnumEncodeError::Discriminant)?;
addr.encode(stream).map_err(EnumEncodeError::Field)?;
0x6u8.encode(output).map_err(EnumEncodeError::BadDiscriminant)?;
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.
#[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();
value.encode(stream)
value.encode(output)
}
}
@ -428,9 +430,9 @@ impl Encode for Ipv6Addr {
/// Encodes the address's bits in big-endian.
#[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();
value.encode(stream)
value.encode(output)
}
}
@ -439,12 +441,12 @@ impl Encode for isize {
/// Casts `self` to [`i16`] and encodes the result.
#[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)
.map_err(|_| IsizeEncodeError(*self))?;
value.encode(stream).unwrap();
Ok(())
let Ok(_) = value.encode(output);
Result::Ok(())
}
}
@ -452,8 +454,8 @@ impl<T: Encode> Encode for LazyCell<T> {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
T::encode(self, stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, output)
}
}
@ -463,8 +465,8 @@ impl<T: Encode> Encode for LazyLock<T> {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
T::encode(self, stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, output)
}
}
@ -474,19 +476,19 @@ impl<T: Encode<Error = E>, E> Encode for LinkedList<T> {
type Error = CollectionEncodeError<UsizeEncodeError, (usize, E)>;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self
.len()
.encode(stream)
.map_err(CollectionEncodeError::Length)?;
.encode(output)
.map_err(CollectionEncodeError::BadLength)?;
for (i, v) in self.iter().enumerate() {
v
.encode(stream)
.map_err(|e| CollectionEncodeError::Item((i, e)))?;
.encode(output)
.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;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self
.lock()
.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.
///
/// 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 {
None => {
false.encode(stream).unwrap();
false
.encode(output)
.map_err::<Self::Error, _>(|_v| unreachable!())?;
}
Some(ref v) => {
true.encode(stream).unwrap();
v.encode(stream)?;
true
.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;
#[inline(always)]
fn encode(&self, _stream: &mut OStream) -> Result<(), Self::Error> {
Ok(())
fn encode(&self, _output: &mut Output) -> Result<(), Self::Error> {
Result::Ok(())
}
}
@ -540,8 +547,8 @@ impl Encode for PhantomPinned {
type Error = Infallible;
#[inline(always)]
fn encode(&self, _stream: &mut OStream) -> Result<(), Self::Error> {
Ok(())
fn encode(&self, _output: &mut Output) -> Result<(), Self::Error> {
Result::Ok(())
}
}
@ -549,11 +556,11 @@ impl<T: Encode> Encode for Range<T> {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.start.encode(stream)?;
self.end.encode(stream)?;
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.start.encode(output)?;
self.end.encode(output)?;
Ok(())
Result::Ok(())
}
}
@ -561,8 +568,8 @@ impl<T: Encode> Encode for RangeFrom<T> {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.start.encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.start.encode(output)
}
}
@ -570,8 +577,8 @@ impl Encode for RangeFull {
type Error = Infallible;
#[inline(always)]
fn encode(&self, _stream: &mut OStream) -> Result<(), Self::Error> {
Ok(())
fn encode(&self, _output: &mut Output) -> Result<(), Self::Error> {
Result::Ok(())
}
}
@ -579,11 +586,11 @@ impl<T: Encode> Encode for RangeInclusive<T> {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.start().encode(stream)?;
self.end().encode(stream)?;
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.start().encode(output)?;
self.end().encode(output)?;
Ok(())
Result::Ok(())
}
}
@ -591,8 +598,8 @@ impl<T: Encode> Encode for RangeTo<T> {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.end.encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.end.encode(output)
}
}
@ -600,10 +607,10 @@ impl<T: Encode> Encode for RangeToInclusive<T> {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.end.encode(stream)?;
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.end.encode(output)?;
Ok(())
Result::Ok(())
}
}
@ -613,8 +620,8 @@ impl<T: Encode + ?Sized> Encode for Rc<T> {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
T::encode(self, stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
T::encode(self, output)
}
}
@ -622,21 +629,22 @@ impl<T: Encode + ?Sized> Encode for RefCell<T> {
type Error = RefCellEncodeError<T::Error>;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
let value = self.try_borrow()
.map_err(RefCellEncodeError::Borrow)?;
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
let value = self
.try_borrow()
.map_err(RefCellEncodeError::BadBorrow)?;
T::encode(&value, stream)
.map_err(RefCellEncodeError::Value)?;
T::encode(&value, output)
.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
T: Encode<Error = Err>,
E: Encode<Error = Err>,
E: Encode<Error: Into<Err>>,
{
type Error = Err;
@ -645,23 +653,25 @@ where
///
/// If `Ok`, then the contained value is encoded after this sign.
#[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
// `true` for `Err` objects.
match *self {
Ok(ref v) => {
false.encode(stream).unwrap();
v.encode(stream)?;
let Ok(_) = false.encode(output);
v.encode(output)?;
}
Err(ref e) => {
true.encode(stream).unwrap();
e.encode(stream)?;
let Ok(_) = true.encode(output);
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;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self
.read()
.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;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.0.encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
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 is then followed by the respective address' own encoding (either [`SocketAddrV4`] or [`SocketAddrV6`]).
#[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.
match *self {
Self::V4(ref addr) => {
0x4u8.encode(stream)?;
addr.encode(stream)?;
0x4u8.encode(output)?;
addr.encode(output)?;
}
Self::V6(ref addr) => {
0x6u8.encode(stream)?;
addr.encode(stream)?;
0x6u8.encode(output)?;
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.
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.ip().encode(stream)?;
self.port().encode(stream)?;
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.ip().encode(output)?;
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.
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.ip().encode(stream)?;
self.port().encode(stream)?;
self.flowinfo().encode(stream)?;
self.scope_id().encode(stream)?;
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.ip().encode(output)?;
self.port().encode(output)?;
self.flowinfo().encode(output)?;
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.
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.as_bytes().encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_bytes().encode(output)
}
}
@ -758,8 +768,8 @@ impl Encode for String {
/// See [`str`].
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.as_str().encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_str().encode(output)
}
}
@ -772,7 +782,7 @@ impl Encode for SystemTime {
///
/// Examples of some timestamps and their encodings include:
///
/// | ISO 8601 | UNIX / Librum |
/// | ISO 8601 | UNIX / oct |
/// | :-------------------------- | -------------: |
/// | `2024-11-03T12:02:01+01:00` | +1730631721 |
/// | `1989-06-03T20:00:00+09:00` | +13258800 |
@ -780,7 +790,7 @@ impl Encode for SystemTime {
/// | `1945-05-04T18:30:00+02:00` | -778231800 |
#[expect(clippy::cast_possible_wrap)]
#[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 duration = self
.duration_since(UNIX_EPOCH)
@ -795,8 +805,8 @@ impl Encode for SystemTime {
0x0 - duration.as_secs() as i64
};
time.encode(stream).unwrap();
Ok(())
time.encode(output)?;
Result::Ok(())
}
}
@ -804,8 +814,8 @@ impl Encode for () {
type Error = Infallible;
#[inline(always)]
fn encode(&self, _stream: &mut OStream) -> Result<(), Self::Error> {
Ok(())
fn encode(&self, _output: &mut Output) -> Result<(), Self::Error> {
Result::Ok(())
}
}
@ -814,12 +824,12 @@ impl Encode for usize {
/// Casts `self` to [`u16`] and encodes the result.
#[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)
.map_err(|_| UsizeEncodeError(*self))?;
.map_err(|_e| UsizeEncodeError(*self))?;
value.encode(stream).unwrap();
Ok(())
let Ok(_) = value.encode(output);
Result::Ok(())
}
}
@ -829,8 +839,8 @@ impl<T: Encode> Encode for Vec<T> {
type Error = <[T] as Encode>::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.as_slice().encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_slice().encode(output)
}
}
@ -838,21 +848,21 @@ impl<T: Encode> Encode for Wrapping<T> {
type Error = T::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.0.encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.0.encode(output)
}
}
macro_rules! impl_numeric {
($ty:ty$(,)?) => {
impl ::librum::Encode for $ty {
impl ::oct::encode::Encode for $ty {
type Error = ::core::convert::Infallible;
#[inline]
fn encode(&self, stream: &mut OStream) -> ::core::result::Result<(), Self::Error> {
stream.write(&self.to_le_bytes());
fn encode(&self, output: &mut Output) -> ::core::result::Result<(), Self::Error> {
output.write(&self.to_le_bytes()).unwrap();
Ok(())
Result::Ok(())
}
}
};
@ -863,20 +873,20 @@ macro_rules! impl_tuple {
$($captures:ident: $tys:ident),+$(,)?
} => {
#[doc(hidden)]
impl<$($tys, )* E> ::librum::Encode for ($($tys, )*)
impl<$($tys, )* E> ::oct::encode::Encode for ($($tys, )*)
where
$($tys: Encode<Error = E>, )* {
type Error = E;
#[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;
$(
$captures.encode(stream)?;
$captures.encode(output)?;
)*
Ok(())
Result::Ok(())
}
}
};
@ -884,12 +894,12 @@ macro_rules! impl_tuple {
macro_rules! impl_non_zero {
($ty:ty$(,)?) => {
impl ::librum::Encode for ::core::num::NonZero<$ty> {
type Error = <$ty as ::librum::Encode>::Error;
impl ::oct::encode::Encode for ::core::num::NonZero<$ty> {
type Error = <$ty as ::oct::encode::Encode>::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> ::core::result::Result<(), Self::Error> {
self.get().encode(stream)
fn encode(&self, output: &mut ::oct::encode::Output) -> ::core::result::Result<(), Self::Error> {
self.get().encode(output)
}
}
};
@ -903,15 +913,17 @@ macro_rules! impl_atomic {
} => {
#[cfg(target_has_atomic = $width)]
#[cfg_attr(doc, doc(cfg(target_has_atomic = $width)))]
impl ::librum::Encode for $atomic_ty {
type Error = <$ty as ::librum::Encode>::Error;
impl ::oct::encode::Encode for $atomic_ty {
type Error = <$ty as ::oct::encode::Encode>::Error;
/// 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.
#[inline(always)]
fn encode(&self, stream: &mut ::librum::OStream) -> ::core::result::Result<(), Self::Error> {
self.load(::std::sync::atomic::Ordering::Relaxed).encode(stream)
fn encode(&self, output: &mut ::oct::encode::Output) -> ::core::result::Result<(), Self::Error> {
use ::std::sync::atomic::Ordering;
self.load(Ordering::Relaxed).encode(output)
}
}
};

View file

@ -1,6 +1,6 @@
// Copyright 2024 Gabriel Bjørnager Jensen.
//
// This file is part of librum.
// This file is part of oct.
//test!(you can redistribut => []);
// it and/or modify it under the terms of the GNU
// Lesser General Public License as published by
@ -8,17 +8,18 @@
// of the License, or (at your option) any later
// 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
// 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
// er General Public License along with oct. If
// 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::{SystemTime, UNIX_EPOCH};
use std::vec;
@ -30,10 +31,10 @@ macro_rules! test {
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();
let len = stream.close();
let len = stream.position();
assert_eq!(&buf[..len], data.as_slice());
}};
}
@ -68,7 +69,7 @@ fn test_encode() {
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]);

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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
#[cfg(test)]
mod tests;
use crate::Encode;
use crate::encode::Encode;
use core::cell::{Cell, LazyCell, RefCell};
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.
///
/// 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 {
/// 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 {
($ty:ty$(,)?) => {
impl ::librum::SizedEncode for $ty {
impl ::oct::encode::SizedEncode for $ty {
const MAX_ENCODED_SIZE: usize = size_of::<$ty>();
}
};
@ -289,18 +289,18 @@ macro_rules! impl_tuple {
$($tys:ident),+$(,)?
} => {
#[doc(hidden)]
impl<$($tys, )* E> ::librum::SizedEncode for ($($tys, )*)
impl<$($tys, )* E> ::oct::encode::SizedEncode for ($($tys, )*)
where
$($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 {
($ty:ty$(,)?) => {
impl ::librum::SizedEncode for ::core::num::NonZero<$ty> {
const MAX_ENCODED_SIZE: usize = <$ty as ::librum::SizedEncode>::MAX_ENCODED_SIZE;
impl ::oct::encode::SizedEncode for ::core::num::NonZero<$ty> {
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_attr(doc, doc(cfg(target_has_atomic = $width)))]
impl ::librum::SizedEncode for $atomic_ty {
const MAX_ENCODED_SIZE: usize = <$ty as ::librum::SizedEncode>::MAX_ENCODED_SIZE;
impl ::oct::encode::SizedEncode for $atomic_ty {
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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// 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::marker::PhantomData;
use std::net::{
@ -34,7 +35,7 @@ use std::num::NonZero;
macro_rules! assert_encoded_size {
($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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::error::Error;
@ -24,7 +24,7 @@ use core::fmt::{self, Display, Formatter};
/// 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).
/// 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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
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.
///
/// 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)]
#[must_use]
pub struct CharDecodeError {

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::convert::Infallible;
@ -26,11 +26,11 @@ use core::fmt::{self, Display, Formatter};
/// A collection could not be decoded.
///
/// 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.
///
/// 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)]
#[must_use]
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).
///
/// 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.
///
/// Sometimes the index of the item may be desired.
/// In these cases the [`ItemDecodeError`](crate::error::ItemDecodeError) could be used here.
Item(I),
BadItem(I),
}
impl<L, I> Display for CollectionDecodeError<L, I>
@ -55,13 +55,11 @@ where
{
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use CollectionDecodeError::*;
match *self {
Length(ref e)
Self::BadLength(ref e)
=> write!(f, "unable to decode collection length: {e}"),
Item(ref e)
Self::BadItem(ref e)
=> write!(f, "unable to decode collection item: {e}"),
}
}
@ -74,12 +72,10 @@ where
{
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
use CollectionDecodeError::*;
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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::convert::Infallible;
@ -26,15 +26,15 @@ use core::fmt::{self, Display, Formatter};
/// A collection could not be encoded.
///
/// 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)]
#[must_use]
pub enum CollectionEncodeError<L, I> {
/// The collection length could not be encoded.
Length(L),
BadLength(L),
/// A collection item could not be encoded.
Item(I),
BadItem(I),
}
impl<L, I> Display for CollectionEncodeError<L, I>
@ -44,13 +44,11 @@ where
{
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use CollectionEncodeError::*;
match *self {
Length(ref e)
Self::BadLength(ref e)
=> write!(f, "unable to encode collection length: {e}"),
Item(ref e)
Self::BadItem(ref e)
=> write!(f, "unable to encode collection item: {e}"),
}
}
@ -63,12 +61,10 @@ where
{
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
use CollectionEncodeError::*;
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!()
}
}

View file

@ -1,25 +1,25 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::Decode;
use crate::decode::Decode;
use core::convert::Infallible;
use core::error::Error;
@ -42,7 +42,7 @@ pub enum EnumDecodeError<D: Decode, F> {
},
/// A field could not be encoded.
Field(F),
BadField(F),
}
impl<D, F> Display for EnumDecodeError<D, F>
@ -52,16 +52,14 @@ where
{
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use EnumDecodeError::*;
match *self {
InvalidDiscriminant(ref e)
Self::InvalidDiscriminant(ref 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"),
Field(ref e)
Self::BadField(ref e)
=> write!(f, "variant could not be decoded: {e}"),
}
}
@ -74,12 +72,10 @@ where
{
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
use EnumDecodeError::*;
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,
}

View file

@ -1,25 +1,25 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::Encode;
use crate::encode::Encode;
use core::convert::Infallible;
use core::error::Error;
@ -30,10 +30,10 @@ use core::fmt::{self, Debug, Display, Formatter};
#[must_use]
pub enum EnumEncodeError<D: Encode, F> {
/// The discriminant could not be encoded.
Discriminant(D::Error),
BadDiscriminant(D::Error),
/// A field could not be encoded.
Field(F),
BadField(F),
}
impl<D, F> Display for EnumEncodeError<D, F>
@ -43,13 +43,11 @@ where
{
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use EnumEncodeError::*;
match *self {
Discriminant(ref e)
Self::BadDiscriminant(ref e)
=> write!(f, "discriminant could not be encoded: {e}"),
Field(ref e)
Self::BadField(ref e)
=> write!(f, "field could not be encoded: {e}"),
}
}
@ -62,12 +60,10 @@ where
{
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
use EnumEncodeError::*;
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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::{Decode, PrimitiveDiscriminant};
use crate::PrimitiveDiscriminant;
use crate::decode::Decode;
use crate::error::{
BoolDecodeError,
CollectionDecodeError,
CStringDecodeError,
EnumDecodeError,
ItemDecodeError,
NonZeroDecodeError,
SizeError,
LengthError,
Utf8Error,
SystemTimeDecodeError,
};
#[cfg(feature = "alloc")]
use crate::error::CStringDecodeError;
use core::convert::Infallible;
use core::error::Error;
use core::fmt::{self, Display, Formatter};
@ -48,9 +50,6 @@ pub enum GenericDecodeError {
/// A string contained a non-UTF-8 sequence.
BadString(Utf8Error),
/// A boolean was neither `false` nor `true`.
InvalidBool(BoolDecodeError),
/// A C-like string contained a null byte.
#[cfg(feature = "std")]
#[cfg_attr(doc, doc(cfg(feature = "std")))]
@ -60,7 +59,7 @@ pub enum GenericDecodeError {
NullInteger(NonZeroDecodeError),
/// A statically-sized buffer was too small.
SmallBuffer(SizeError),
SmallBuffer(LengthError),
/// An unassigned discriminant value was encountered.
///
@ -79,29 +78,24 @@ pub enum GenericDecodeError {
impl Display for GenericDecodeError {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use GenericDecodeError::*;
match *self {
BadString(ref e)
Self::BadString(ref e)
=> write!(f, "{e}"),
InvalidBool(ref e)
Self::NullString(ref e)
=> write!(f, "{e}"),
NullString(ref e)
Self::NullInteger(ref e)
=> write!(f, "{e}"),
NullInteger(ref e)
Self::SmallBuffer(ref e)
=> write!(f, "{e}"),
SmallBuffer(ref e)
=> write!(f, "{e}"),
UnassignedDiscriminant { value }
Self::UnassignedDiscriminant { value }
=> write!(f, "discriminant value `{value:#X} has not been assigned"),
#[cfg(feature = "std")]
NarrowSystemTime(ref e)
Self::NarrowSystemTime(ref e)
=> write!(f, "{e}"),
}
}
@ -110,35 +104,24 @@ impl Display for GenericDecodeError {
impl Error for GenericDecodeError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
use GenericDecodeError::*;
match *self {
BadString(ref e) => Some(e),
InvalidBool(ref e) => Some(e),
Self::BadString(ref e) => Some(e),
#[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")]
NarrowSystemTime(ref e) => Some(e),
Self::NarrowSystemTime(ref e) => Some(e),
_ => 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
where
L: Into<Self>,
@ -146,16 +129,25 @@ where
{
#[inline(always)]
fn from(value: CollectionDecodeError<L, I>) -> Self {
use CollectionDecodeError::*;
use CollectionDecodeError as Error;
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
where
D: Decode<Error: Into<Self>> + PrimitiveDiscriminant,
@ -163,14 +155,14 @@ where
{
#[inline(always)]
fn from(value: EnumDecodeError<D, F>) -> Self {
use EnumDecodeError::*;
use EnumDecodeError as Error;
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 {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed
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 {
#[inline(always)]
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)]
fn from(value: SizeError) -> Self {
fn from(value: LengthError) -> Self {
Self::SmallBuffer(value)
}
}

View file

@ -1,25 +1,25 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::Encode;
use crate::encode::Encode;
use crate::error::{
CollectionEncodeError,
EnumEncodeError,
@ -36,7 +36,7 @@ use core::hint::unreachable_unchecked;
/// 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.
#[derive(Debug)]
#[must_use]
@ -55,31 +55,29 @@ pub enum GenericEncodeError {
impl Display for GenericEncodeError {
#[inline]
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 {
BadBorrow(ref e) => e,
Self::LargeIsize(ref 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 {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
use GenericEncodeError::*;
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)]
fn from(value: CollectionEncodeError<L, I>) -> Self {
use CollectionEncodeError::*;
use CollectionEncodeError as Error;
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)]
fn from(value: EnumEncodeError<D, F>) -> Self {
use EnumEncodeError::*;
use EnumEncodeError as Error;
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 {
#[inline(always)]
fn from(_value: Infallible) -> Self {
// SAFETY: `Infallible` objects can never be con-
// structed
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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::error::Error;
@ -35,7 +35,13 @@ pub struct IsizeEncodeError(
impl Display for IsizeEncodeError {
#[inline(always)]
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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::convert::Infallible;

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::convert::Infallible;

View file

@ -1,49 +1,50 @@
// 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
// 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
// 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 Librum. If
// 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};
/// 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)).
/// 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.
/// It is allowed for any smaller-sized `SizedSlice` instance to decode a larger-sized encoding **if** the actual length still fits.
/// If not, then this error type is used to denote the error state.
/// 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 is still within bounds.
/// Otherwise, this error type is used to denote the error state.
#[derive(Debug)]
#[must_use]
pub struct SizeError {
pub struct LengthError {
/// The total capacity of the buffer.
pub cap: usize,
pub capacity: usize,
/// The required amount of elements.
pub len: usize,
}
impl Display for SizeError {
impl Display for LengthError {
#[inline(always)]
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.
//
// 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
// 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
// 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 Librum. If
// 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 Librum.
//! 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 bool_decode_error);
use_mod!(pub char_decode_error);
use_mod!(pub collection_decode_error);
use_mod!(pub collection_encode_error);
use_mod!(pub enum_encode_error);
use_mod!(pub enum_decode_error);
use_mod!(pub enum_encode_error);
use_mod!(pub generic_decode_error);
use_mod!(pub generic_encode_error);
use_mod!(pub input_error);
use_mod!(pub isize_encode_error);
use_mod!(pub item_decode_error);
use_mod!(pub item_encode_error);
use_mod!(pub length_error);
use_mod!(pub non_zero_decode_error);
use_mod!(pub output_error);
use_mod!(pub ref_cell_encode_error);
use_mod!(pub size_error);
use_mod!(pub string_error);
use_mod!(pub usize_encode_error);
use_mod!(pub utf16_error);

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::error::Error;
@ -24,7 +24,7 @@ use core::fmt::{self, Display, Formatter};
/// 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)]
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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::cell::BorrowError;
@ -25,28 +25,26 @@ use core::fmt::{self, Display, Formatter};
/// 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>.
/// If this call fails, then the returned error is again returned as a [`Borrow`](Self::Borrow) 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.
/// 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 [`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 [`BadValue`](Self::BadValue) instance.
#[derive(Debug)]
#[must_use]
pub enum RefCellEncodeError<E> {
/// The reference cell could not be borrowed.
Borrow(BorrowError),
BadBorrow(BorrowError),
/// The contained value could not be encoded.
Value(E),
BadValue(E),
}
impl<E: Display> Display for RefCellEncodeError<E> {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use RefCellEncodeError::*;
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}")
@ -56,12 +54,10 @@ impl<E: Display> Display for RefCellEncodeError<E> {
impl<E: Error + 'static> Error for RefCellEncodeError<E> {
#[inline(always)]
fn source(&self) -> Option<&(dyn Error + 'static)> {
use RefCellEncodeError::*;
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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// 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::fmt::{self, Display, Formatter};
@ -36,22 +36,20 @@ pub enum StringError {
BadUtf8(Utf8Error),
/// A fixed-size buffer was too small.
SmallBuffer(SizeError),
SmallBuffer(LengthError),
}
impl Display for StringError {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use StringError::*;
match *self {
BadUtf16(ref e)
Self::BadUtf16(ref e)
=> write!(f, "bad utf-16: {e}"),
BadUtf8(ref e)
Self::BadUtf8(ref e)
=> write!(f, "bad utf-8: {e}"),
SmallBuffer(ref e)
Self::SmallBuffer(ref e)
=> write!(f, "buffer too small: {e}"),
}
}
@ -60,14 +58,12 @@ impl Display for StringError {
impl Error for StringError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
use StringError::*;
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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::error::Error;

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::error::Error;
@ -35,7 +35,12 @@ pub struct UsizeEncodeError(
impl Display for UsizeEncodeError {
#[inline(always)]
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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::error::Error;

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use core::error::Error;

View file

@ -1,29 +1,29 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// 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.
//! Therefore, this crate may be more suited for networking or other cases where many allocations are unwanted.
//!
@ -34,24 +34,25 @@
//!
//! # 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.
//! 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:
//! 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 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_u32` | 1.130 | 1.084 | 0.749 | 2.793 |
//! | `encode_u128` | 2.340 | 2.328 | 1.543 | 6.380 |
//! | `encode_u8` | 0.968 | 0.857 | 0.733 | 0.979 |
//! | `encode_u32` | 1.065 | 0.999 | 0.730 | 2.727 |
//! | `encode_u128` | 2.168 | 2.173 | 1.510 | 6.246 |
//! | `encode_struct_unit` | 0.000 | 0.000 | 0.000 | 0.000 |
//! | `encode_struct_unnamed` | 1.218 | 1.160 | 0.838 | 2.392 |
//! | `encode_struct_named` | 3.077 | 1.501 | 0.975 | 3.079 |
//! | `encode_enum_unit` | 0.260 | 0.310 | 0.000 | 0.303 |
//! | `decode_u8` | 1.116 | 1.106 | 1.110 | 1.102 |
//! | `decode_non_zero_u8` | 1.228 | 1.236 | 1.269 | 1.263 |
//! | **Total time** &#8594; | 11.373 | 9.672 | 7.291 | 18.284 |
//! | **Total deviation (p.c.)** &#8594; | +56 | +33 | ±0 | +150 |
//! | `encode_struct_unnamed` | 1.241 | 1.173 | 0.823 | 3.350 |
//! | `encode_struct_named` | 3.079 | 1.507 | 0.973 | 3.082 |
//! | `encode_enum_unit` | 0.246 | 0.297 | 0.000 | 0.295 |
//! | `decode_u8` | 0.942 | 0.962 | 0.922 | 0.923 |
//! | `decode_non_zero_u8` | 1.126 | 1.159 | 1.127 | 1.160 |
//! | `decode_bool` | 1.040 | 1.099 | 1.055 | 1.177 |
//! | **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/
//! [Borsh]: https://crates.io/crates/borsh/
@ -59,9 +60,9 @@
//!
//! 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.
//! Do feel free to conduct your own tests of Librum.
//! Do feel free to conduct your own tests of oct.
//!
//! # Data model
//!
@ -78,16 +79,18 @@
//!
//! # 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.
//!
//! 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:
//!
//! ```
//! use librum::{Buf, Decode, Encode};
//! use oct::Slot;
//! use oct::decode::Decode;
//! use oct::encode::Encode;
//!
//! #[derive(Debug, Decode, Encode, PartialEq)]
//! struct Ints {
@ -106,7 +109,7 @@
//! 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();
//!
@ -127,20 +130,20 @@
//!
//! ## 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).
//! The [`Buf`] type can be used to handle these streams.
//! These streams are separated into two type: [*output streams*](encode::Output) and [*input streams*](decode::Input).
//! The [`Slot`] type can be used to handle these streams.
//!
//! ## Encoding
//!
//! To encode an object directly using the `Encode` trait, simply allocate a buffer for the encoding and wrap it in an [`OStream`] object:
//! To encode an object directly using the `Encode` trait, simply allocate a buffer for the encoding and wrap it in an `Output` object:
//!
//! ```
//! use librum::{Encode, OStream, SizedEncode};
//! use oct::encode::{Encode, Output, SizedEncode};
//!
//! 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();
//!
@ -150,10 +153,10 @@
//! 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 stream = OStream::new(&mut buf);
//! let mut stream = Output::new(&mut buf);
//!
//! // Note: For serialising multiple characters, the
//! // `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 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 mut stream = IStream::new(&data);
//! let mut stream = Input::new(&data);
//!
//! assert_eq!(u16::decode(&mut stream).unwrap(), 0x4554);
//!
//! // 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(), 0x45);
//!
//! // Including as tuples:
//!
//! stream = IStream::new(&data);
//! stream = Input::new(&data);
//!
//! assert_eq!(<(u8, u8)>::decode(&mut stream).unwrap(), (0x54, 0x45));
//! ```
@ -206,7 +209,9 @@
//! 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::net::{SocketAddr, ToSocketAddrs, UdpSocket};
//! use std::thread::spawn;
@ -242,8 +247,8 @@
//! struct Party {
//! pub socket: UdpSocket,
//!
//! pub request_buf: Buf::<Request>,
//! pub response_buf: Buf::<Response>,
//! pub request_buf: Slot::<Request>,
//! pub response_buf: Slot::<Response>,
//! }
//!
//! impl Party {
@ -253,8 +258,8 @@
//! let this = Self {
//! socket,
//!
//! request_buf: Buf::new(),
//! response_buf: Buf::new(),
//! request_buf: Slot::new(),
//! response_buf: Slot::new(),
//! };
//!
//! Ok(this)
@ -307,28 +312,28 @@
//!
//! # 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)
//! * *`proc-macro`: Pulls the procedural macros from the [`librum-macros`](https://crates.io/crates/librum-macros/) crate
//! * *`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 [`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)
//!
//! Features marked with * are enabled by default.
//!
//! # Documentation
//!
//! Librum has its documentation written in-source for use by `rustdoc`.
//! See [Docs.rs](https://docs.rs/librum/latest/librum/) for an on-line, rendered instance.
//! oct has its documentation written in-source for use by `rustdoc`.
//! 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.
//! The nightly toolchain is therefore required when rendering them.
//!
//! # 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.
//!
//! 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
//!
@ -344,13 +349,13 @@
#![no_std]
#![warn(missing_docs)]
#![cfg_attr(doc, allow(internal_features))]
#![cfg_attr(doc, feature(doc_cfg, rustdoc_internals))]
#![deny(missing_docs)]
// For use in macros:
extern crate self as librum;
extern crate self as oct;
#[cfg(feature = "alloc")]
extern crate alloc;
@ -358,116 +363,6 @@ extern crate alloc;
#[cfg(feature = "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 {
($vis:vis $name:ident$(,)?) => {
mod $name;
@ -476,18 +371,14 @@ macro_rules! 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 sized_encode);
use_mod!(pub sized_iter);
use_mod!(pub sized_slice);
use_mod!(pub sized_str);
#[cfg(feature = "alloc")]
use_mod!(pub buf);
use_mod!(pub slot);
pub mod decode;
pub mod encode;
pub mod error;

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
mod sealed {
@ -46,16 +46,15 @@ pub trait PrimitiveDiscriminant: Copy + SealedPrimitiveDiscriminant + Sized { }
macro_rules! impl_primitive_discriminant {
($ty:ty) => {
impl ::librum::SealedPrimitiveDiscriminant for $ty {
impl ::oct::SealedPrimitiveDiscriminant for $ty {
#[allow(clippy::cast_lossless)]
#[inline(always)]
#[must_use]
fn to_u128(self) -> 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.
//
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
#[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> {
#[inline]
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 start = pos;

View file

@ -1,25 +1,25 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use librum::{SizedSlice, SizedStr};
use oct::{SizedSlice, SizedStr};
#[test]
fn test_sized_iter_clone() {

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::SizedSlice;
@ -93,4 +93,4 @@ impl<T: PartialOrd, const N: usize> PartialOrd<Vec<T>> for SizedSlice<T, N> {
fn partial_cmp(&self, other: &Vec<T>) -> Option<Ordering> {
self.as_slice().partial_cmp(other.as_slice())
}
}
}

View file

@ -1,50 +1,44 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::{
Decode,
DecodeBorrowed,
Encode,
IStream,
OStream,
SizedEncode,
SizedSlice
};
use crate::error::{CollectionDecodeError, ItemDecodeError, SizeError};
use crate::SizedSlice;
use crate::decode::{Decode, DecodeBorrowed, Input};
use crate::encode::{Encode, Output, SizedEncode};
use crate::error::{CollectionDecodeError, ItemDecodeError, LengthError};
use core::mem::MaybeUninit;
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]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap();
if len > N { return Err(CollectionDecodeError::Length(SizeError { cap: N, len })) };
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let len = Decode::decode(input).unwrap();
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() {
let v = Decode::decode(stream)
.map_err(|e| CollectionDecodeError::Item(ItemDecodeError { index: i, error: e }))?;
let v = Decode::decode(input)
.map_err(|e| CollectionDecodeError::BadItem(ItemDecodeError { index: i, error: e }))?;
slot.write(v);
}
@ -59,11 +53,11 @@ impl<T: Encode, const N: usize> Encode for SizedSlice<T, N> {
type Error = <[T] as Encode>::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.as_slice().encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_slice().encode(output)
}
}
impl<T: SizedEncode, const N: usize> SizedEncode for SizedSlice<T, N> {
const MAX_ENCODED_SIZE: usize = T::MAX_ENCODED_SIZE * N;
}
}

View file

@ -1,26 +1,26 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::SizedSlice;
use crate::error::SizeError;
use crate::error::LengthError;
use core::borrow::{Borrow, BorrowMut};
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> {
type Error = SizeError;
type Error = LengthError;
#[inline(always)]
fn try_from(value: &[T]) -> Result<Self, Self::Error> {

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
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 {
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;
for item in &mut buf {

View file

@ -1,28 +1,28 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
#[cfg(test)]
mod tests;
use crate::error::SizeError;
use crate::error::LengthError;
use core::fmt::{self, Debug, Formatter};
use core::hash::{Hash, Hasher};
@ -31,6 +31,9 @@ use core::ops::{Index, IndexMut};
use core::ptr::{copy_nonoverlapping, null, null_mut};
use core::slice::SliceIndex;
// Encode/decode facilities:
mod code;
// Conversion facilities:
mod conv;
@ -40,12 +43,9 @@ mod cmp;
// Iterator facilities:
mod iter;
// Encode/decode facilities:
mod serdes;
/// 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`.
///
@ -56,7 +56,7 @@ mod serdes;
/// 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 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> {
/// Constructs an empty, fixed-size vector.
#[inline]
pub fn new(data: &[T]) -> Result<Self, SizeError> {
let mut buf: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
pub fn new(data: &[T]) -> Result<Self, LengthError> {
let mut buf = [const { MaybeUninit::<T>::uninit() };N];
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()) {
item.write(value.clone());

View file

@ -1,25 +1,25 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use librum::SizedSlice;
use oct::SizedSlice;
use std::vec::Vec;
#[test]

View file

@ -1,22 +1,22 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::SizedStr;

View file

@ -1,49 +1,43 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::{
Decode,
DecodeBorrowed,
Encode,
IStream,
OStream,
SizedEncode,
SizedStr
};
use crate::error::{CollectionDecodeError, SizeError, StringError, Utf8Error};
use crate::SizedStr;
use crate::decode::{Decode, DecodeBorrowed, Input};
use crate::encode::{Encode, Output, SizedEncode};
use crate::error::{CollectionDecodeError, LengthError, StringError, Utf8Error};
impl<const N: usize> Decode for SizedStr<N> {
type Error = CollectionDecodeError<SizeError, Utf8Error>;
type Error = CollectionDecodeError<LengthError, Utf8Error>;
#[inline]
fn decode(stream: &mut IStream) -> Result<Self, Self::Error> {
let len = Decode::decode(stream).unwrap();
fn decode(input: &mut Input) -> Result<Self, Self::Error> {
let len = Decode::decode(input).unwrap();
let data = stream.read(len);
let data = input.read(len).unwrap();
Self::from_utf8(data)
.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!(),
})
@ -56,8 +50,8 @@ impl<const N: usize> Encode for SizedStr<N> {
type Error = <str as Encode>::Error;
#[inline(always)]
fn encode(&self, stream: &mut OStream) -> Result<(), Self::Error> {
self.as_str().encode(stream)
fn encode(&self, output: &mut Output) -> Result<(), Self::Error> {
self.as_str().encode(output)
}
}

View file

@ -1,26 +1,26 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use crate::{SizedSlice, SizedStr};
use crate::error::{SizeError, StringError, Utf8Error};
use crate::error::{LengthError, StringError, Utf8Error};
use core::borrow::{Borrow, BorrowMut};
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.
#[inline]
pub const fn from_utf8(data: &[u8]) -> Result<Self, StringError> {
if data.len() > N { return Err(StringError::SmallBuffer(SizeError { cap: N, len: data.len() })) };
pub const fn from_utf8(s: &[u8]) -> Result<Self, StringError> {
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,
Err(e) => {
let i = e.valid_up_to();
let c = data[i];
let c = s[i];
return Err(StringError::BadUtf8(Utf8Error { value: c, index: i }));
}
@ -295,7 +295,7 @@ impl<const N: usize> FromStr for SizedStr<N> {
#[inline]
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()) };
Ok(this)

View file

@ -1,29 +1,29 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
#[cfg(test)]
mod tests;
use crate::SizedSlice;
use crate::error::{SizeError, StringError};
use crate::error::{LengthError, StringError};
use core::fmt::{self, Debug, Display, Formatter};
use core::hash::{Hash, Hasher};
@ -34,12 +34,12 @@ use core::str::{Chars, CharIndices};
// Comparison facilities:
mod cmp;
// Encode/decode facilities:
mod code;
// Conversion facilities:
mod conv;
// Encode/decode facilities:
mod serdes;
/// 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.
@ -56,7 +56,7 @@ mod serdes;
/// Therefore, the following four strings have -- despite their different contents -- the same total size.
///
/// ```
/// use librum::SizedStr;
/// use oct::SizedStr;
/// use std::str::FromStr;
///
/// 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.
#[inline(always)]
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()) };
Ok(this)
@ -201,4 +201,3 @@ impl<I: SliceIndex<str>, const N: usize> IndexMut<I> for SizedStr<N> {
self.get_mut(index).unwrap()
}
}

View file

@ -1,26 +1,26 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use librum::SizedStr;
use librum::error::{StringError, Utf8Error};
use oct::SizedStr;
use oct::error::{StringError, Utf8Error};
use std::cmp::Ordering;
#[test]

View file

@ -1,34 +1,29 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
#[cfg(test)]
mod tests;
use crate::{
Decode,
Encode,
IStream,
OStream,
SizedEncode,
};
use crate::decode::{Decode, Input};
use crate::encode::{Encode, Output, SizedEncode};
use alloc::boxed::Box;
use alloc::vec;
@ -39,7 +34,7 @@ use core::ops::{Deref, DerefMut, Index, IndexMut};
use core::ptr::{self, copy_nonoverlapping};
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.
///
@ -48,16 +43,11 @@ use core::slice::{self, SliceIndex};
///
/// # Examples
///
/// Create a buffer for holding a `Request` enumeration:
/// Create a slot for holding a `Request` enumeration:
///
/// ```
/// use librum::{
/// Buf,
/// Encode,
/// OStream,
/// SizedEncode,
/// SizedStr,
/// };
/// use oct::{SizedStr, Slot};
/// use oct::encode::{Encode, Output, SizedEncode};
///
/// #[derive(Debug, Encode, SizedEncode)]
/// enum Request {
@ -68,15 +58,15 @@ use core::slice::{self, SliceIndex};
/// SendMessage { message: SizedStr<0x80> },
/// }
///
/// let mut buf = Buf::new();
/// let mut buf = Slot::new();
///
/// buf.write(Request::Join { username: "epsiloneridani".parse().unwrap() }).unwrap();
/// 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")))]
pub struct Buf<T> {
pub struct Slot<T> {
buf: Box<[u8]>,
len: usize,
@ -84,8 +74,8 @@ pub struct Buf<T> {
}
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> Buf<T> {
/// Allocates a new buffer suitable for encoding.
impl<T> Slot<T> {
/// Allocates a new slot suitable for encodings.
///
/// 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
///
@ -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).
#[inline(always)]
@ -135,7 +125,7 @@ impl<T> Buf<T> {
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).
#[inline(always)]
@ -144,10 +134,10 @@ impl<T> Buf<T> {
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)).
/// This is in contrast to [`as_mut_slice`](Self::as_mut_slice), which references the entire buffer.
/// 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 slot buffer.
#[inline(always)]
#[must_use]
pub fn as_slice(&self) -> &[u8] {
@ -155,9 +145,9 @@ impl<T> Buf<T> {
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.
#[inline(always)]
@ -167,7 +157,7 @@ impl<T> Buf<T> {
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.
///
@ -176,7 +166,7 @@ impl<T> Buf<T> {
pub fn copy_from_slice(&mut self, data: &[u8]) {
let len = data.len();
assert!(len <= self.capacity(), "buffer cannot contain source slice");
assert!(len <= self.capacity(), "slot cannot contain source slice");
unsafe {
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)).
/// For the same operation *without* these checks, see [`set_len_unchecked`](Self::set_len_unchecked).
///
/// # 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.
#[inline(always)]
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.
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.
/// For the same operation *with* checks, see [`set_len`](Self::set_len).
///
/// # 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.
#[inline(always)]
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
// caller.
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.
#[inline(always)]
#[must_use]
@ -237,18 +227,18 @@ impl<T> Buf<T> {
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).
///
/// For retrieving the capacity of the buffer, see [`capacity`](Self::capacity).
/// For retrieving the capacity of the slot, see [`capacity`](Self::capacity).
#[inline(always)]
#[must_use]
pub fn len(&self) -> usize {
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.
#[inline(always)]
@ -257,7 +247,7 @@ impl<T> Buf<T> {
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).
#[inline(always)]
@ -268,8 +258,8 @@ impl<T> Buf<T> {
}
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T: Encode> Buf<T> {
/// Encodes an object into the buffer.
impl<T: Encode> Slot<T> {
/// 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>.
///
@ -278,11 +268,11 @@ impl<T: Encode> Buf<T> {
/// Any error that occurs during encoding is passed on and returned from this method.
#[inline]
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)?;
let len = stream.close();
let len = stream.position();
self.set_len(len);
Ok(())
@ -290,8 +280,8 @@ impl<T: Encode> Buf<T> {
}
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T: Decode> Buf<T> {
/// Decodes an object from the buffer.
impl<T: Decode> Slot<T> {
/// 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>.
///
@ -303,10 +293,10 @@ impl<T: Decode> Buf<T> {
/// Any error that occurs during decoding is passed on and returned from this method.
#[inline]
pub fn read(&self) -> Result<T, T::Error> {
// We should only pass the used part of the buffer
// to `deserialise`.
// We should only pass the used part of the slot to
// `decode`.
let mut stream = IStream::new(&self.buf);
let mut stream = Input::new(&self.buf);
let value = Decode::decode(&mut stream)?;
Ok(value)
@ -314,10 +304,10 @@ impl<T: Decode> Buf<T> {
}
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T: SizedEncode> Buf<T> {
/// Allocates a new buffer suitable for encoding.
impl<T: SizedEncode> Slot<T> {
/// 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.
#[inline(always)]
#[must_use]
@ -328,7 +318,7 @@ impl<T: SizedEncode> Buf<T> {
/// See also [`as_mut_slice`](Self::as_mut_slice).
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> AsMut<[u8]> for Buf<T> {
impl<T> AsMut<[u8]> for Slot<T> {
#[inline(always)]
fn as_mut(&mut self) -> &mut [u8] {
self.as_mut_slice()
@ -337,7 +327,7 @@ impl<T> AsMut<[u8]> for Buf<T> {
/// See also [`as_slice`](Self::as_slice).
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> AsRef<[u8]> for Buf<T> {
impl<T> AsRef<[u8]> for Slot<T> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self.as_slice()
@ -346,7 +336,7 @@ impl<T> AsRef<[u8]> for Buf<T> {
/// See also [`as_slice`](Self::as_slice).
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> Borrow<[u8]> for Buf<T> {
impl<T> Borrow<[u8]> for Slot<T> {
#[inline(always)]
fn borrow(&self) -> &[u8] {
self.as_slice()
@ -355,7 +345,7 @@ impl<T> Borrow<[u8]> for Buf<T> {
/// See also [`as_mut_slice`](Self::as_mut_slice).
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> BorrowMut<[u8]> for Buf<T> {
impl<T> BorrowMut<[u8]> for Slot<T> {
#[inline(always)]
fn borrow_mut(&mut self) -> &mut [u8] {
self.as_mut_slice()
@ -363,13 +353,13 @@ impl<T> BorrowMut<[u8]> for Buf<T> {
}
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> Debug for Buf<T> {
impl<T> Debug for Slot<T> {
#[inline(always)]
fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{:?}", self.as_slice()) }
}
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T: SizedEncode> Default for Buf<T> {
impl<T: SizedEncode> Default for Slot<T> {
#[inline(always)]
fn default() -> Self {
Self::new()
@ -377,7 +367,7 @@ impl<T: SizedEncode> Default for Buf<T> {
}
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> Deref for Buf<T> {
impl<T> Deref for Slot<T> {
type Target = [u8];
#[inline(always)]
@ -387,7 +377,7 @@ impl<T> Deref for Buf<T> {
}
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> DerefMut for Buf<T> {
impl<T> DerefMut for Slot<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
@ -395,7 +385,7 @@ impl<T> DerefMut for Buf<T> {
}
#[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;
#[inline(always)]
@ -405,7 +395,7 @@ impl<T, I: SliceIndex<[u8]>> Index<I> for Buf<T> {
}
#[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)]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
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")))]
impl<T> PartialEq<[u8]> for Buf<T> {
impl<T> PartialEq<[u8]> for Slot<T> {
#[inline(always)]
fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other
@ -421,7 +411,7 @@ impl<T> PartialEq<[u8]> for Buf<T> {
}
#[cfg_attr(doc, doc(cfg(feature = "alloc")))]
impl<T> PartialEq<&[u8]> for Buf<T> {
impl<T> PartialEq<&[u8]> for Slot<T> {
#[inline(always)]
fn eq(&self, other: &&[u8]) -> bool {
self.as_slice() == *other
@ -429,7 +419,7 @@ impl<T> PartialEq<&[u8]> for Buf<T> {
}
#[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)]
fn eq(&self, other: &&mut [u8]) -> bool {
self.as_slice() == *other

View file

@ -1,30 +1,30 @@
// 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
// 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
// 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 Librum. If
// er General Public License along with oct. If
// not, see <https://www.gnu.org/licenses/>.
use librum::Buf;
use librum::error::CharDecodeError;
use oct::Slot;
use oct::error::CharDecodeError;
#[test]
fn test_buf_write_read() {
let mut buf = Buf::<char>::new();
let mut buf = Slot::<char>::new();
macro_rules! test_read {
($pattern:pat$(,)?) => {{