caio.co/de/foca

Use Error trait from core

This patch gets rid of the `anyhow` dependency in favor of
`core::error::Error` and sets the MSRV to 1.81.0
Id
f93b2020a487186b9298ceecb859c0921c013a24
Author
Caio
Commit time
2024-09-05T23:37:01+02:00

Modified Cargo.toml

@@ -1,7 +1,7
[package]
name = "foca"
version = "0.17.2"
-rust-version = "1.70.0"
+rust-version = "1.81.0"
authors = ["Caio <contact@caio.co>"]
edition = "2021"
license = "MPL-2.0"
@@ -20,7 +20,7
default = []

# Adds compatibility with some types and traits
-std = ["anyhow/std"]
+std = []
# Exposes `BincodeCodec` a lean general-purpose std-only codec
bincode-codec = ["std", "serde", "bincode", "bytes/std"]
# Exposes `PostcardCodec`, a no_std-friendly codec
@@ -29,7 +29,6
[dependencies]
rand = { version = "0.8", default-features = false }
bytes = { version = "1", default-features = false }
-anyhow = { version = "1", default-features = false }

serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true }
bincode = { version = "1", default-features = false, optional = true }

Modified examples/foca_insecure_udp_agent.rs

@@ -546,10 +546,21
}
}

+#[derive(Debug)]
+struct Msg(String);
+
+impl core::fmt::Display for Msg {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl core::error::Error for Msg {}
+
impl foca::BroadcastHandler<ID> for Handler {
type Key = BroadcastKey;

- type Error = String;
+ type Error = Msg;

fn receive_item(
&mut self,
@@ -565,7 +576,7
let Broadcast { key, msg }: Broadcast = self
.opts
.deserialize_from(&mut reader)
- .map_err(|err| format!("bad broadcast: {err}"))?;
+ .map_err(|err| Msg(format!("bad broadcast: {err}")))?;

let is_new_message = self
.messages

Modified src/broadcast.rs

@@ -1,8 +1,8
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use alloc::vec::Vec;
-use core::{cmp::Ordering, fmt};
+use core::cmp::Ordering;

use bytes::BufMut;

@@ -21,7 +21,7

/// The error type that `receive_item` may emit. Will be wrapped
/// by [`crate::Error::CustomBroadcast`].
- type Error: fmt::Debug + fmt::Display + Send + Sync + 'static;
+ type Error: core::error::Error + Send + 'static;

/// Decodes a [`Self::Key`] from a buffer and either discards
/// it or tells Foca to persist and disseminate it.

Modified src/error.rs

@@ -1,8 +1,10
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use core::fmt;

+use alloc::boxed::Box;
+
#[derive(Debug)]
/// This type represents all possible errors operating a Foca instance.
pub enum Error {
@@ -63,17 +65,17
/// codec.
///
/// Might have left Foca in a inconsistent state.
- Encode(anyhow::Error),
+ Encode(Box<dyn core::error::Error + Send>),

/// Wraps [`crate::Codec`]'s `decode_*` failures.
///
/// Can happen during normal operation when receiving junk data.
- Decode(anyhow::Error),
+ Decode(Box<dyn core::error::Error + Send>),

/// Wraps [`crate::BroadcastHandler`] failures.
///
/// Doesn't affect Foca's state.
- CustomBroadcast(anyhow::Error),
+ CustomBroadcast(Box<dyn core::error::Error + Send>),

/// Configuration change not allowed.
///

Modified src/lib.rs

@@ -116,7 +116,7
)]

extern crate alloc;
-use alloc::vec::Vec;
+use alloc::{boxed::Box, vec::Vec};

#[cfg(feature = "std")]
extern crate std;
@@ -206,6 +206,7
where
T: Identity,
C: Codec<T>,
+ C::Error: core::error::Error + Send,
RNG: Rng,
{
/// Create a new Foca instance with custom broadcasts disabled.
@@ -233,17 +234,14
}
}

-// XXX Does it make sense to have different associated type restrictions
-// based on a feature flag? Say: when using `std` we would enforce
-// that `Codec::Error` and `BroadcastHandler::Error` both implement
-// `std::error::Error`, thus instead of wrapping these errors via
-// `anyhow::Error::msg` we can use `anyhow::Error::new`.
impl<T, C, RNG, B> Foca<T, C, RNG, B>
where
T: Identity,
C: Codec<T>,
+ C::Error: core::error::Error,
RNG: Rng,
B: BroadcastHandler<T>,
+ B::Error: core::error::Error + 'static,
{
/// Initialize a new Foca instance.
pub fn with_custom_broadcast(
@@ -589,8 +587,7
if let Some(key) = self
.broadcast_handler
.receive_item(data, None)
- .map_err(anyhow::Error::msg)
- .map_err(Error::CustomBroadcast)?
+ .map_err(|e| Error::CustomBroadcast(Box::new(e)))?
{
self.custom_broadcasts.add_or_replace(
key,
@@ -878,8 +875,7
let header = self
.codec
.decode_header(&mut data)
- .map_err(anyhow::Error::msg)
- .map_err(Error::Decode)?;
+ .map_err(|e| Error::Decode(Box::new(e)))?;

#[cfg(feature = "tracing")]
span.record("header", tracing::field::debug(&header));
@@ -918,8 +914,7
self.member_buf.push(
self.codec
.decode_member(&mut data)
- .map_err(anyhow::Error::msg)
- .map_err(Error::Decode)?,
+ .map_err(|e| Error::Decode(Box::new(e)))?,
);
}
}
@@ -1097,8 +1092,7
let mut buf = Vec::new();
self.codec
.encode_member(&member, &mut buf)
- .map_err(anyhow::Error::msg)
- .map_err(Error::Encode)?;
+ .map_err(|e| Error::Encode(Box::new(e)))?;

Ok(buf)
}
@@ -1306,8 +1300,7
if let Some(key) = self
.broadcast_handler
.receive_item(pkt, sender)
- .map_err(anyhow::Error::msg)
- .map_err(Error::CustomBroadcast)?
+ .map_err(|e| Error::CustomBroadcast(Box::new(e)))?
{
#[cfg(feature = "tracing")]
tracing::trace!(len = pkt_len, "received broadcast item");
@@ -1434,8 +1427,7
if let Err(err) = self
.codec
.encode_header(&header, &mut buf)
- .map_err(anyhow::Error::msg)
- .map_err(Error::Encode)
+ .map_err(|e| Error::Encode(Box::new(e)))
{
debug_assert_eq!(0, self.send_buf.capacity(), "send_buf modified while taken");
self.send_buf = buf.into_inner();
@@ -1681,8 +1673,7
}
}

-#[cfg(feature = "std")]
-impl std::error::Error for BroadcastsDisabledError {}
+impl core::error::Error for BroadcastsDisabledError {}

impl<T> BroadcastHandler<T> for NoCustomBroadcast {
type Key = &'static [u8];
@@ -1712,8 +1703,10
where
T: Identity,
C: Codec<T>,
+ C::Error: core::error::Error,
RNG: rand::Rng,
B: BroadcastHandler<T>,
+ B::Error: core::error::Error + Send,
{
pub fn incarnation(&self) -> Incarnation {
self.incarnation
@@ -1872,6 +1865,8
}
}

+ impl core::error::Error for UnitError {}
+
impl Codec<ID> for UnitErroringCodec {
type Error = UnitError;

@@ -1918,12 +1913,12
let mut foca = Foca::new(ID::new(1), Config::simple(), rng(), UnitErroringCodec);

assert_eq!(
- Err(Error::Encode(anyhow::Error::msg(UnitError))),
+ Err(Error::Encode(alloc::boxed::Box::new(UnitError))),
foca.announce(ID::new(2), NoopRuntime)
);

assert_eq!(
- Err(Error::Decode(anyhow::Error::msg(UnitError))),
+ Err(Error::Decode(alloc::boxed::Box::new(UnitError))),
foca.handle_data(b"hue", NoopRuntime)
);
}
@@ -3425,9 +3420,9
buf.get_u16()
}

- fn from_bytes(mut src: impl Buf) -> core::result::Result<Self, &'static str> {
+ fn from_bytes(mut src: impl Buf) -> core::result::Result<Self, Msg> {
if src.remaining() < 10 {
- Err("buffer too small")
+ Err(Msg("buffer too small"))
} else {
let mut data = [0u8; 10];
let mut buf = &mut data[..];
@@ -3458,10 +3453,21
use alloc::collections::BTreeMap;
struct Handler(BTreeMap<u64, u16>);

+ #[derive(Debug)]
+ struct Msg(&'static str);
+
+ impl core::fmt::Display for Msg {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+ }
+
+ impl core::error::Error for Msg {}
+
impl BroadcastHandler<ID> for Handler {
type Key = VersionedKey;

- type Error = &'static str;
+ type Error = Msg;

fn receive_item(
&mut self,
@@ -4349,10 +4355,21
}
}

+ #[derive(Debug)]
+ struct Msg(&'static str);
+
+ impl core::fmt::Display for Msg {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+ }
+
+ impl core::error::Error for Msg {}
+
impl BroadcastHandler<ID> for DumbHandler {
type Key = GrowOnly;

- type Error = &'static str;
+ type Error = Msg;

fn receive_item(
&mut self,

Modified src/testing.rs

@@ -118,6 +118,8
}
}

+impl core::error::Error for BadCodecError {}
+
impl BadCodec {
fn encode_header(
&self,