rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 heartwoodb23e506ff82fa349e2a95222efe3bd6934e7f290
{
"request": "trigger",
"version": 1,
"event_type": "patch",
"repository": {
"id": "rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5",
"name": "heartwood",
"description": "Radicle Heartwood Protocol & Stack",
"private": false,
"default_branch": "master",
"delegates": [
"did:key:z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT",
"did:key:z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW",
"did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
"did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz"
]
},
"action": "Updated",
"patch": {
"id": "2b670a8e593667c3ce872296382d1fe8561937bd",
"author": {
"id": "did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz",
"alias": "lorenz"
},
"title": "radicle-protocol: A Sans I/O Implementation of the Network Protocol",
"state": {
"status": "open",
"conflicts": []
},
"before": "fb8681f5bc5460a7970f023d61b272d0a1474711",
"after": "b23e506ff82fa349e2a95222efe3bd6934e7f290",
"commits": [
"b23e506ff82fa349e2a95222efe3bd6934e7f290",
"e2d98f1d4c657e3e5c3c92f9f3cea9d5aa080d1f",
"c72ff4d7adb09865b525137c443a891112f80308",
"6aecac5744b076cb2f06987281f42b907a6d4a69"
],
"target": "fb8681f5bc5460a7970f023d61b272d0a1474711",
"labels": [],
"assignees": [],
"revisions": [
{
"id": "2b670a8e593667c3ce872296382d1fe8561937bd",
"author": {
"id": "did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz",
"alias": "lorenz"
},
"description": "As of 2025-06 this is just an early draft.\n\nThe `radicle-protocol` was initialized by moving files out of `radicle-node`, and adjusting `use`s.\n\n`radicle-node` and `radicle-protocol` use `radicle::node::Link` instead of `netservices::LinkDirection`, to remove the dependency on `netservices` for `radicle-protocol`. To allow a \"drop-in\", a few backward compatible extensions were added to `radicle::node::Link`.\n\nThe encoding and decoding layer of `radicle-node` was refactored to use `bytes` without `std::io::Error` instead of `byteorder` and `std::io:Error`.\nThe dependency on `byteorder` was not completely removed from the Cargo workspace, as other crates use it in other ways.",
"base": "af35e6f4d04735c33cc10777d6421a61555db754",
"oid": "5e47e09f965b517e62bb829b7c214cd68472e6f9",
"timestamp": 1750668729
},
{
"id": "ec0b79bb9c3d51dbf8d7154cc2c7abdefccf9537",
"author": {
"id": "did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz",
"alias": "lorenz"
},
"description": "Rebase",
"base": "fb8681f5bc5460a7970f023d61b272d0a1474711",
"oid": "b23e506ff82fa349e2a95222efe3bd6934e7f290",
"timestamp": 1752682320
}
]
}
}
{
"response": "triggered",
"run_id": {
"id": "31de768b-be18-4ab7-9637-0c3f74b4908e"
},
"info_url": "https://cci.rad.levitte.org//31de768b-be18-4ab7-9637-0c3f74b4908e.html"
}
Started at: 2025-07-16 18:16:23.178405+02:00
Commands:
$ rad clone rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 .
✓ Creating checkout in ./...
✓ Remote cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT added
✓ Remote-tracking branch cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT/master created for z6MksFq…bS9wzpT
✓ Remote cloudhead@z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW added
✓ Remote-tracking branch cloudhead@z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW/master created for z6MktaN…hzPZRZW
✓ Remote fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM added
✓ Remote-tracking branch fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM/master created for z6Mkire…SQZ3voM
✓ Remote erikli@z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz added
✓ Remote-tracking branch erikli@z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz/master created for z6MkgFq…FGAnBGz
✓ Remote lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz added
✓ Remote-tracking branch lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz/master created for z6MkkPv…WX5sTEz
✓ Repository successfully cloned under /opt/radcis/ci.rad.levitte.org/cci/state/31de768b-be18-4ab7-9637-0c3f74b4908e/w/
╭────────────────────────────────────╮
│ heartwood │
│ Radicle Heartwood Protocol & Stack │
│ 112 issues · 13 patches │
╰────────────────────────────────────╯
Run `cd ./.` to go to the repository directory.
Exit code: 0
$ rad patch checkout 2b670a8e593667c3ce872296382d1fe8561937bd
✓ Switched to branch patch/2b670a8 at revision ec0b79b
✓ Branch patch/2b670a8 setup to track rad/patches/2b670a8e593667c3ce872296382d1fe8561937bd
Exit code: 0
$ git config advice.detachedHead false
Exit code: 0
$ git checkout b23e506ff82fa349e2a95222efe3bd6934e7f290
HEAD is now at b23e506f protocol: Reimplement encoding on top of `bytes`
Exit code: 0
$ git show b23e506ff82fa349e2a95222efe3bd6934e7f290
commit b23e506ff82fa349e2a95222efe3bd6934e7f290
Author: Lorenz Leutgeb <lorenz.leutgeb@radicle.xyz>
Date: Sat Jun 21 18:44:14 2025 +0200
protocol: Reimplement encoding on top of `bytes`
diff --git a/Cargo.lock b/Cargo.lock
index 2991484a..c7bd35bb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -349,6 +349,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+[[package]]
+name = "bytes"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+
[[package]]
name = "bytesize"
version = "2.0.1"
@@ -2636,7 +2642,7 @@ dependencies = [
"amplify",
"anyhow",
"bloomy",
- "byteorder",
+ "bytes",
"chrono",
"colored",
"crossbeam-channel",
@@ -2673,7 +2679,7 @@ name = "radicle-protocol"
version = "0.1.0"
dependencies = [
"bloomy",
- "byteorder",
+ "bytes",
"crossbeam-channel",
"cyphernet",
"fastrand",
diff --git a/Cargo.toml b/Cargo.toml
index 3a3920fd..ebe95903 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,7 +22,7 @@ rust-version = "1.81.0"
amplify = { version = "4.0.0", default-features = false }
anyhow = "1"
bstr = "1.3"
-byteorder = "1.4"
+bytes = "1"
chrono = { version = "0.4.26", default-features = false }
colored = "2.1.0"
crossbeam-channel = "0.5.6"
diff --git a/crates/radicle-node/Cargo.toml b/crates/radicle-node/Cargo.toml
index ce05ef47..85e2720a 100644
--- a/crates/radicle-node/Cargo.toml
+++ b/crates/radicle-node/Cargo.toml
@@ -18,7 +18,7 @@ test = ["radicle/test", "radicle-crypto/test", "radicle-crypto/cyphernet", "radi
amplify = { workspace = true }
anyhow = { workspace = true }
bloomy = "1.2"
-byteorder = { workspace = true }
+bytes = { workspace = true }
chrono = { workspace = true, features = ["clock"] }
colored = { workspace = true }
crossbeam-channel = { workspace = true }
diff --git a/crates/radicle-node/src/tests.rs b/crates/radicle-node/src/tests.rs
index 82e5e83f..a265bc93 100644
--- a/crates/radicle-node/src/tests.rs
+++ b/crates/radicle-node/src/tests.rs
@@ -79,8 +79,8 @@ fn test_inventory_decode() {
let timestamp: Timestamp = LocalTime::now().into();
let mut buf = Vec::new();
- inventory.as_slice().encode(&mut buf).unwrap();
- timestamp.encode(&mut buf).unwrap();
+ inventory.as_slice().encode(&mut buf);
+ timestamp.encode(&mut buf);
let m = InventoryAnnouncement::decode(&mut buf.as_slice()).expect("message decodes");
assert_eq!(inventory.as_slice(), m.inventory.as_slice());
diff --git a/crates/radicle-node/src/wire.rs b/crates/radicle-node/src/wire.rs
index 4a3e0553..3033b353 100644
--- a/crates/radicle-node/src/wire.rs
+++ b/crates/radicle-node/src/wire.rs
@@ -1001,9 +1001,7 @@ where
metrics.sent_gossip_messages += msgs.len();
for msg in msgs {
- Frame::gossip(link, msg)
- .encode(&mut data)
- .expect("in-memory writes never fail");
+ Frame::gossip(link, msg).encode(&mut data);
}
metrics.sent_bytes += data.len();
@@ -1262,18 +1260,16 @@ mod test {
let pong = Message::Pong {
zeroes: ZeroBytes::new(42),
};
- frame::PROTOCOL_VERSION_STRING.encode(&mut stream).unwrap();
- frame::StreamId::gossip(Link::Outbound)
- .encode(&mut stream)
- .unwrap();
+ frame::PROTOCOL_VERSION_STRING.encode(&mut stream);
+ frame::StreamId::gossip(Link::Outbound).encode(&mut stream);
// Serialize gossip message with some extension fields.
let mut gossip = wire::serialize(&pong);
- String::from("extra").encode(&mut gossip).unwrap();
- 48u8.encode(&mut gossip).unwrap();
+ String::from("extra").encode(&mut gossip);
+ 48u8.encode(&mut gossip);
// Encode gossip message using the varint-prefix format into the stream.
- varint::payload::encode(&gossip, &mut stream).unwrap();
+ varint::payload::encode(&gossip, &mut stream);
let mut de = deserializer::Deserializer::<1024, Frame>::new(1024);
de.input(&stream).unwrap();
@@ -1298,16 +1294,14 @@ mod test {
}
impl wire::Encode for MessageWithExt {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = self.msg.encode(writer)?;
- n += self.ext.encode(writer)?;
-
- Ok(n)
+ fn encode(&self, writer: &mut impl bytes::BufMut) {
+ self.msg.encode(writer);
+ self.ext.encode(writer);
}
}
impl wire::Decode for MessageWithExt {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
+ fn decode(reader: &mut impl bytes::Buf) -> Result<Self, wire::Error> {
let msg = Message::decode(reader)?;
let ext = String::decode(reader).unwrap_or_default();
@@ -1337,12 +1331,9 @@ mod test {
ext: String::from("extra"),
},
)
- .encode(&mut stream)
- .unwrap();
+ .encode(&mut stream);
// Pong message that comes after, without extension.
- frame::Frame::gossip(Link::Outbound, pong.clone())
- .encode(&mut stream)
- .unwrap();
+ frame::Frame::gossip(Link::Outbound, pong.clone()).encode(&mut stream);
// First test deserializing using the message with extension type.
{
diff --git a/crates/radicle-protocol/Cargo.toml b/crates/radicle-protocol/Cargo.toml
index 6a301073..e96c1221 100644
--- a/crates/radicle-protocol/Cargo.toml
+++ b/crates/radicle-protocol/Cargo.toml
@@ -13,7 +13,7 @@ test = ["radicle/test", "radicle-crypto/test", "radicle-crypto/cyphernet", "qche
[dependencies]
bloomy = "1.2"
-byteorder = { workspace = true }
+bytes = { workspace = true }
crossbeam-channel = { workspace = true }
cyphernet = { workspace = true, features = ["tor"] }
fastrand = { workspace = true }
diff --git a/crates/radicle-protocol/src/bounded.rs b/crates/radicle-protocol/src/bounded.rs
index e136bc31..1687de4b 100644
--- a/crates/radicle-protocol/src/bounded.rs
+++ b/crates/radicle-protocol/src/bounded.rs
@@ -28,7 +28,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
/// # Examples
///
/// ```
- /// use radicle_node::bounded;
+ /// use radicle_protocol::bounded;
///
/// let mut iter = (0..4).into_iter();
/// let bounded: bounded::BoundedVec<i32,3> = bounded::BoundedVec::collect_from(&mut iter);
@@ -48,7 +48,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
/// # Examples
///
/// ```
- /// use radicle_node::bounded;
+ /// use radicle_protocol::bounded;
///
/// let mut vec = vec![1, 2, 3];
/// let bounded = bounded::BoundedVec::<_, 2>::truncate(vec);
@@ -64,7 +64,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
/// # Examples
///
/// ```
- /// use radicle_node::bounded;
+ /// use radicle_protocol::bounded;
///
/// let vec = bounded::BoundedVec::<i32, 11>::with_capacity(10).unwrap();
///
@@ -94,7 +94,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
/// # Examples
///
/// ```
- /// use radicle_node::bounded;
+ /// use radicle_protocol::bounded;
///
/// type Inventory = bounded::BoundedVec<(), 10>;
/// assert_eq!(Inventory::max(), 10);
@@ -120,7 +120,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
/// # Examples
///
/// ```
- /// use radicle_node::bounded;
+ /// use radicle_protocol::bounded;
///
/// let mut vec: bounded::BoundedVec<_,3> = vec![1, 2].try_into().unwrap();
/// vec.push(3).expect("within limit");
@@ -147,7 +147,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
/// # Examples
///
/// ```
- /// use radicle_node::bounded;
+ /// use radicle_protocol::bounded;
///
/// let mut bounded: bounded::BoundedVec<_,3> = vec![1, 2, 3].try_into().unwrap();
/// let mut vec = bounded.unbound();
@@ -240,6 +240,51 @@ impl<T: std::fmt::Debug, const N: usize> std::fmt::Debug for BoundedVec<T, N> {
}
}
+unsafe impl<const N: usize> bytes::BufMut for BoundedVec<u8, N> {
+ fn remaining_mut(&self) -> usize {
+ N - self.v.len()
+ }
+
+ unsafe fn advance_mut(&mut self, cnt: usize) {
+ let len = {
+ let len = self.v.len();
+ let remaining = N - len;
+
+ if remaining >= cnt {
+ len + cnt
+ } else {
+ panic!("advance out of bounds: have {remaining} remaining, but advancing by {cnt}",);
+ }
+ };
+
+ debug_assert!(len <= N);
+
+ // Addition will not overflow since the sum is at most the capacity.
+ self.v.set_len(len);
+ }
+
+ fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
+ let len = self.v.len();
+
+ // If the vector is full, we double its capacity using `reserve`, but not beyond the limit.
+ if self.v.capacity() == len {
+ self.v.reserve(std::cmp::min(len, N - len));
+ }
+
+ let cap = self.v.capacity();
+
+ debug_assert!(cap <= N);
+ debug_assert!(len <= cap);
+
+ let ptr = self.v.as_mut_ptr();
+
+ // SAFETY: Since `ptr` is valid for `cap` bytes, `ptr.add(len)` must be
+ // valid for `cap - len` bytes. The subtraction will not underflow since
+ // `len <= cap`.
+ unsafe { bytes::buf::UninitSlice::from_raw_parts_mut(ptr.add(len), cap - len) }
+ }
+}
+
#[cfg(any(test, feature = "test"))]
impl<T, const N: usize> qcheck::Arbitrary for BoundedVec<T, N>
where
diff --git a/crates/radicle-protocol/src/deserializer.rs b/crates/radicle-protocol/src/deserializer.rs
index e75ddeaa..3ddec6a8 100644
--- a/crates/radicle-protocol/src/deserializer.rs
+++ b/crates/radicle-protocol/src/deserializer.rs
@@ -58,7 +58,7 @@ impl<const B: usize, D: wire::Decode> Deserializer<B, D> {
Ok(Some(msg))
}
- Err(err) if err.is_eof() => Ok(None),
+ Err(wire::Error::UnexpectedEnd { .. }) => Ok(None),
Err(err) => Err(err),
}
}
@@ -79,6 +79,20 @@ impl<const B: usize, D: wire::Decode> Deserializer<B, D> {
}
}
+unsafe impl<const B: usize, D: wire::Decode> bytes::BufMut for Deserializer<B, D> {
+ fn remaining_mut(&self) -> usize {
+ self.unparsed.remaining_mut()
+ }
+
+ unsafe fn advance_mut(&mut self, cnt: usize) {
+ self.unparsed.advance_mut(cnt);
+ }
+
+ fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
+ self.unparsed.chunk_mut()
+ }
+}
+
impl<const B: usize, D: wire::Decode> io::Write for Deserializer<B, D> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.input(buf).map_err(|_| io::ErrorKind::OutOfMemory)?;
diff --git a/crates/radicle-protocol/src/service/message.rs b/crates/radicle-protocol/src/service/message.rs
index 5995b748..282cc662 100644
--- a/crates/radicle-protocol/src/service/message.rs
+++ b/crates/radicle-protocol/src/service/message.rs
@@ -1,6 +1,8 @@
-use std::{fmt, io, mem};
+use std::{fmt, mem};
+use bytes::{Buf, BufMut};
use nonempty::NonEmpty;
+
use radicle::crypto;
use radicle::git;
use radicle::identity::RepoId;
@@ -117,32 +119,28 @@ impl NodeAnnouncement {
}
impl wire::Encode for NodeAnnouncement {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = 0;
-
- n += self.version.encode(writer)?;
- n += self.features.encode(writer)?;
- n += self.timestamp.encode(writer)?;
- n += self.alias.encode(writer)?;
- n += self.addresses.encode(writer)?;
- n += self.nonce.encode(writer)?;
- n += self.agent.encode(writer)?;
-
- Ok(n)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.version.encode(buf);
+ self.features.encode(buf);
+ self.timestamp.encode(buf);
+ self.alias.encode(buf);
+ self.addresses.encode(buf);
+ self.nonce.encode(buf);
+ self.agent.encode(buf);
}
}
impl wire::Decode for NodeAnnouncement {
- fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
- let version = u8::decode(reader)?;
- let features = node::Features::decode(reader)?;
- let timestamp = Timestamp::decode(reader)?;
- let alias = wire::Decode::decode(reader)?;
- let addresses = BoundedVec::<Address, ADDRESS_LIMIT>::decode(reader)?;
- let nonce = u64::decode(reader)?;
- let agent = match UserAgent::decode(reader) {
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
+ let version = u8::decode(buf)?;
+ let features = node::Features::decode(buf)?;
+ let timestamp = Timestamp::decode(buf)?;
+ let alias = wire::Decode::decode(buf)?;
+ let addresses = BoundedVec::<Address, ADDRESS_LIMIT>::decode(buf)?;
+ let nonce = u64::decode(buf)?;
+ let agent = match UserAgent::decode(buf) {
Ok(ua) => ua,
- Err(e) if e.is_eof() => UserAgent::default(),
+ Err(wire::Error::UnexpectedEnd { .. }) => UserAgent::default(),
Err(e) => return Err(e),
};
@@ -708,8 +706,8 @@ mod tests {
.signed(&Device::mock())
.into();
- let mut buf: Vec<u8> = Vec::new();
- assert!(msg.encode(&mut buf).is_ok());
+ let mut buf = Vec::new();
+ msg.encode(&mut buf);
let decoded = wire::deserialize(buf.as_slice());
assert!(decoded.is_ok());
@@ -728,10 +726,7 @@ mod tests {
&Device::mock(),
);
let mut buf: Vec<u8> = Vec::new();
- assert!(
- msg.encode(&mut buf).is_ok(),
- "INVENTORY_LIMIT is a valid limit for encoding",
- );
+ msg.encode(&mut buf);
let decoded = wire::deserialize(buf.as_slice());
assert!(
diff --git a/crates/radicle-protocol/src/wire.rs b/crates/radicle-protocol/src/wire.rs
index fb696f1d..d3d9f78e 100644
--- a/crates/radicle-protocol/src/wire.rs
+++ b/crates/radicle-protocol/src/wire.rs
@@ -7,12 +7,13 @@ pub use message::{AddressType, MessageType};
use std::collections::BTreeMap;
use std::convert::TryFrom;
+use std::mem;
use std::ops::Deref;
use std::str::FromStr;
use std::string::FromUtf8Error;
-use std::{io, mem};
-use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
+use bytes::{Buf, BufMut};
+
use cyphernet::addr::tor;
use radicle::crypto::{PublicKey, Signature, Unverified};
@@ -41,8 +42,6 @@ pub type Size = u16;
#[derive(thiserror::Error, Debug)]
pub enum Error {
- #[error("i/o: {0}")]
- Io(#[from] io::Error),
#[error("UTF-8 error: {0}")]
FromUtf8(#[from] FromUtf8Error),
#[error("invalid size: expected {expected}, got {actual}")]
@@ -75,24 +74,32 @@ pub enum Error {
UnknownInfoType(u16),
#[error("unexpected bytes")]
UnexpectedBytes,
-}
-
-impl Error {
- /// Whether we've reached the end of file. This will be true when we fail to decode
- /// a message because there's not enough data in the stream.
- pub fn is_eof(&self) -> bool {
- matches!(self, Self::Io(err) if err.kind() == io::ErrorKind::UnexpectedEof)
+ #[error("unexpected end of buffer, requested {requested} more bytes but only {available} are available")]
+ UnexpectedEnd { available: usize, requested: usize },
+}
+
+impl From<bytes::TryGetError> for Error {
+ fn from(
+ bytes::TryGetError {
+ available,
+ requested,
+ }: bytes::TryGetError,
+ ) -> Self {
+ Self::UnexpectedEnd {
+ available,
+ requested,
+ }
}
}
/// Things that can be encoded as binary.
pub trait Encode {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error>;
+ fn encode(&self, buffer: &mut impl BufMut);
}
/// Things that can be decoded from binary.
pub trait Decode: Sized {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error>;
+ fn decode(buffer: &mut impl Buf) -> Result<Self, Error>;
}
/// Encode an object into a byte vector.
@@ -100,79 +107,62 @@ pub trait Decode: Sized {
/// # Panics
///
/// If the encoded object exceeds [`Size::MAX`].
-pub fn serialize<T: Encode + ?Sized>(data: &T) -> Vec<u8> {
- let mut buffer = Vec::new();
- // SAFETY: We expect this to panic if the user passes
- // in data that exceeds the maximum allowed size.
- #[allow(clippy::unwrap_used)]
- let len = data.encode(&mut buffer).unwrap();
-
- debug_assert_eq!(len, buffer.len());
-
- buffer
+pub fn serialize<E: Encode + ?Sized>(data: &E) -> Vec<u8> {
+ let mut buffer = Vec::new().limit(Size::MAX as usize);
+ data.encode(&mut buffer);
+ buffer.into_inner()
}
-/// Decode an object from a vector.
-pub fn deserialize<T: Decode>(data: &[u8]) -> Result<T, Error> {
- let mut cursor = io::Cursor::new(data);
- let obj = T::decode(&mut cursor)?;
+/// Decode an object from a slice.
+pub fn deserialize<T: Decode>(mut data: &[u8]) -> Result<T, Error> {
+ let result = T::decode(&mut data)?;
- if cursor.position() as usize != cursor.get_ref().len() {
- return Err(Error::UnexpectedBytes);
+ if data.is_empty() {
+ Ok(result)
+ } else {
+ Err(Error::UnexpectedBytes)
}
- Ok(obj)
}
impl Encode for u8 {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- writer.write_u8(*self)?;
-
- Ok(mem::size_of::<Self>())
+ fn encode(&self, buf: &mut impl BufMut) {
+ buf.put_u8(*self);
}
}
impl Encode for u16 {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- writer.write_u16::<NetworkEndian>(*self)?;
-
- Ok(mem::size_of::<Self>())
+ fn encode(&self, buf: &mut impl BufMut) {
+ buf.put_u16(*self);
}
}
impl Encode for u32 {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- writer.write_u32::<NetworkEndian>(*self)?;
-
- Ok(mem::size_of::<Self>())
+ fn encode(&self, buf: &mut impl BufMut) {
+ buf.put_u32(*self);
}
}
impl Encode for u64 {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- writer.write_u64::<NetworkEndian>(*self)?;
-
- Ok(mem::size_of::<Self>())
+ fn encode(&self, buf: &mut impl BufMut) {
+ buf.put_u64(*self);
}
}
impl Encode for PublicKey {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.deref().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.deref().encode(buf)
}
}
impl<const T: usize> Encode for &[u8; T] {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- writer.write_all(&**self)?;
- Ok(mem::size_of::<Self>())
+ fn encode(&self, buf: &mut impl BufMut) {
+ buf.put_slice(&**self);
}
}
impl<const T: usize> Encode for [u8; T] {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- writer.write_all(self)?;
-
- Ok(mem::size_of::<Self>())
+ fn encode(&self, buf: &mut impl BufMut) {
+ buf.put_slice(self);
}
}
@@ -180,13 +170,12 @@ impl<T> Encode for &[T]
where
T: Encode,
{
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = (self.len() as Size).encode(writer)?;
+ fn encode(&self, buf: &mut impl BufMut) {
+ (self.len() as Size).encode(buf);
for item in self.iter() {
- n += item.encode(writer)?;
+ item.encode(buf);
}
- Ok(n)
}
}
@@ -194,75 +183,72 @@ impl<T, const N: usize> Encode for BoundedVec<T, N>
where
T: Encode,
{
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.as_slice().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.as_slice().encode(buf)
}
}
impl Encode for &str {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
+ fn encode(&self, buf: &mut impl BufMut) {
assert!(self.len() <= u8::MAX as usize);
- let n = (self.len() as u8).encode(writer)?;
+ (self.len() as u8).encode(buf);
let bytes = self.as_bytes();
// Nb. Don't use the [`Encode`] instance here for &[u8], because we are prefixing the
// length ourselves.
- writer.write_all(bytes)?;
-
- Ok(n + bytes.len())
+ buf.put_slice(bytes);
}
}
impl Encode for String {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.as_str().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.as_str().encode(buf)
}
}
impl Encode for git::Url {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.to_string().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.to_string().encode(buf)
}
}
impl Encode for RepoId {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.deref().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.deref().encode(buf)
}
}
impl Encode for Refs {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
+ fn encode(&self, buf: &mut impl BufMut) {
let len: Size = self
.len()
.try_into()
- .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
- let mut n = len.encode(writer)?;
+ .expect("`Refs::len()` must be less than or equal to `Size::MAX`");
+ len.encode(buf);
for (name, oid) in self.iter() {
- n += name.as_str().encode(writer)?;
- n += oid.encode(writer)?;
+ name.as_str().encode(buf);
+ oid.encode(buf);
}
- Ok(n)
}
}
impl Encode for cyphernet::addr::tor::OnionAddrV3 {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.into_raw_bytes().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.into_raw_bytes().encode(buf)
}
}
impl Encode for UserAgent {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.as_ref().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.as_ref().encode(buf)
}
}
impl Encode for Alias {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.as_ref().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.as_ref().encode(buf)
}
}
@@ -271,51 +257,50 @@ where
A: Encode,
B: Encode,
{
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = self.0.encode(writer)?;
- n += self.1.encode(writer)?;
- Ok(n)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.0.encode(buf);
+ self.1.encode(buf);
}
}
impl Encode for git::RefString {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.as_str().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.as_str().encode(buf)
}
}
impl Encode for Signature {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.deref().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.deref().encode(buf)
}
}
impl Encode for git::Oid {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
+ fn encode(&self, buf: &mut impl BufMut) {
// Nb. We use length-encoding here to support future SHA-2 object ids.
- self.as_bytes().encode(writer)
+ self.as_bytes().encode(buf)
}
}
////////////////////////////////////////////////////////////////////////////////
impl Decode for PublicKey {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let buf: [u8; 32] = Decode::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let buf: [u8; 32] = Decode::decode(buf)?;
Ok(PublicKey::from(buf))
}
}
impl Decode for Refs {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let len = Size::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let len = Size::decode(buf)?;
let mut refs = BTreeMap::new();
for _ in 0..len {
- let name = String::decode(reader)?;
+ let name = String::decode(buf)?;
let name = git::RefString::try_from(name).map_err(Error::from)?;
- let oid = git::Oid::decode(reader)?;
+ let oid = git::Oid::decode(buf)?;
refs.insert(name, oid);
}
@@ -324,22 +309,21 @@ impl Decode for Refs {
}
impl Decode for git::RefString {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let ref_str = String::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let ref_str = String::decode(buf)?;
git::RefString::try_from(ref_str).map_err(Error::from)
}
}
impl Decode for UserAgent {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- String::decode(reader)
- .and_then(|s| UserAgent::from_str(&s).map_err(Error::InvalidUserAgent))
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ String::decode(buf).and_then(|s| UserAgent::from_str(&s).map_err(Error::InvalidUserAgent))
}
}
impl Decode for Alias {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- String::decode(reader).and_then(|s| Alias::from_str(&s).map_err(Error::from))
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ String::decode(buf).and_then(|s| Alias::from_str(&s).map_err(Error::from))
}
}
@@ -348,16 +332,16 @@ where
A: Decode,
B: Decode,
{
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let a = A::decode(reader)?;
- let b = B::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let a = A::decode(buf)?;
+ let b = B::decode(buf)?;
Ok((a, b))
}
}
impl Decode for git::Oid {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let len = Size::decode(reader)? as usize;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let len = Size::decode(buf)? as usize;
#[allow(non_upper_case_globals)]
const expected: usize = mem::size_of::<git::raw::Oid>();
@@ -368,7 +352,7 @@ impl Decode for git::Oid {
});
}
- let buf: [u8; expected] = Decode::decode(reader)?;
+ let buf: [u8; expected] = Decode::decode(buf)?;
let oid = git::raw::Oid::from_bytes(&buf).expect("the buffer is exactly the right size");
let oid = git::Oid::from(oid);
@@ -377,41 +361,41 @@ impl Decode for git::Oid {
}
impl Decode for Signature {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let bytes: [u8; 64] = Decode::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let bytes: [u8; 64] = Decode::decode(buf)?;
Ok(Signature::from(bytes))
}
}
impl Decode for u8 {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- reader.read_u8().map_err(Error::from)
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ Ok(buf.try_get_u8()?)
}
}
impl Decode for u16 {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- reader.read_u16::<NetworkEndian>().map_err(Error::from)
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ Ok(buf.try_get_u16()?)
}
}
impl Decode for u32 {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- reader.read_u32::<NetworkEndian>().map_err(Error::from)
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ Ok(buf.try_get_u32()?)
}
}
impl Decode for u64 {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- reader.read_u64::<NetworkEndian>().map_err(Error::from)
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ Ok(buf.try_get_u64()?)
}
}
impl<const N: usize> Decode for [u8; N] {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
let mut ary = [0; N];
- reader.read_exact(&mut ary)?;
+ buf.try_copy_to_slice(&mut ary).map_err(Error::from)?;
Ok(ary)
}
@@ -421,15 +405,15 @@ impl<T, const N: usize> Decode for BoundedVec<T, N>
where
T: Decode,
{
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let len: usize = Size::decode(reader)? as usize;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let len: usize = Size::decode(buf)? as usize;
let mut items = Self::with_capacity(len).map_err(|_| Error::InvalidSize {
expected: Self::max(),
actual: len,
})?;
for _ in 0..items.capacity() {
- let item = T::decode(reader)?;
+ let item = T::decode(buf)?;
items.push(item).ok();
}
Ok(items)
@@ -437,11 +421,11 @@ where
}
impl Decode for String {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let len = u8::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let len = u8::decode(buf)?;
let mut bytes = vec![0; len as usize];
- reader.read_exact(&mut bytes)?;
+ buf.try_copy_to_slice(&mut bytes)?;
let string = String::from_utf8(bytes)?;
@@ -450,32 +434,29 @@ impl Decode for String {
}
impl Decode for RepoId {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let oid: git::Oid = Decode::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let oid: git::Oid = Decode::decode(buf)?;
Ok(Self::from(oid))
}
}
impl Encode for filter::Filter {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = 0;
-
- n += self.deref().as_bytes().encode(writer)?;
-
- Ok(n)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.deref().as_bytes().encode(buf);
}
}
impl Decode for filter::Filter {
- fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let size: usize = Size::decode(reader)? as usize;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let size: usize = Size::decode(buf)? as usize;
if !filter::FILTER_SIZES.contains(&size) {
return Err(Error::InvalidFilterSize(size));
}
let mut bytes = vec![0; size];
- reader.read_exact(&mut bytes[..])?;
+
+ buf.try_copy_to_slice(&mut bytes)?;
let f = filter::BloomFilter::from(bytes);
debug_assert_eq!(f.hashes(), filter::FILTER_HASHES);
@@ -485,63 +466,55 @@ impl Decode for filter::Filter {
}
impl<V> Encode for SignedRefs<V> {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = 0;
-
- n += self.id.encode(writer)?;
- n += self.refs.encode(writer)?;
- n += self.signature.encode(writer)?;
-
- Ok(n)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.id.encode(buf);
+ self.refs.encode(buf);
+ self.signature.encode(buf);
}
}
impl Decode for SignedRefs<Unverified> {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let id = NodeId::decode(reader)?;
- let refs = Refs::decode(reader)?;
- let signature = Signature::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let id = NodeId::decode(buf)?;
+ let refs = Refs::decode(buf)?;
+ let signature = Signature::decode(buf)?;
Ok(Self::new(refs, id, signature))
}
}
impl Encode for RefsAt {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = 0;
-
- n += self.remote.encode(writer)?;
- n += self.at.encode(writer)?;
-
- Ok(n)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.remote.encode(buf);
+ self.at.encode(buf);
}
}
impl Decode for RefsAt {
- fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let remote = NodeId::decode(reader)?;
- let at = git::Oid::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let remote = NodeId::decode(buf)?;
+ let at = git::Oid::decode(buf)?;
Ok(Self { remote, at })
}
}
impl Encode for node::Features {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.deref().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.deref().encode(buf)
}
}
impl Decode for node::Features {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let features = u64::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let features = u64::decode(buf)?;
Ok(Self::from(features))
}
}
impl Decode for tor::OnionAddrV3 {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let bytes: [u8; tor::ONION_V3_RAW_LEN] = Decode::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let bytes: [u8; tor::ONION_V3_RAW_LEN] = Decode::decode(buf)?;
let addr = tor::OnionAddrV3::from_raw_bytes(bytes)?;
Ok(addr)
@@ -549,14 +522,14 @@ impl Decode for tor::OnionAddrV3 {
}
impl Encode for Timestamp {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.deref().encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.deref().encode(buf)
}
}
impl Decode for Timestamp {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
- let millis = u64::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
+ let millis = u64::decode(buf)?;
let ts = Timestamp::try_from(millis).map_err(Error::InvalidTimestamp)?;
Ok(ts)
diff --git a/crates/radicle-protocol/src/wire/frame.rs b/crates/radicle-protocol/src/wire/frame.rs
index fcd5c30f..cdf9e3ea 100644
--- a/crates/radicle-protocol/src/wire/frame.rs
+++ b/crates/radicle-protocol/src/wire/frame.rs
@@ -2,9 +2,11 @@
#![warn(clippy::missing_docs_in_private_items)]
use std::{fmt, io};
+use bytes::{Buf, BufMut};
+use radicle::node::Link;
+
use crate::service::Message;
use crate::{wire, wire::varint, wire::varint::VarInt, PROTOCOL_VERSION};
-use radicle::node::Link;
/// Protocol version strings all start with the magic sequence `rad`, followed
/// by a version number.
@@ -29,17 +31,16 @@ impl Version {
}
impl wire::Encode for Version {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- writer.write_all(&PROTOCOL_VERSION_STRING.0)?;
-
- Ok(PROTOCOL_VERSION_STRING.0.len())
+ fn encode(&self, buf: &mut impl BufMut) {
+ buf.put_slice(&PROTOCOL_VERSION_STRING.0);
}
}
impl wire::Decode for Version {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
let mut version = [0u8; 4];
- reader.read_exact(&mut version[..])?;
+
+ buf.try_copy_to_slice(&mut version[..])?;
if version != PROTOCOL_VERSION_STRING.0 {
return Err(wire::Error::InvalidProtocolVersion(version));
@@ -144,15 +145,15 @@ impl fmt::Display for StreamId {
}
impl wire::Decode for StreamId {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
- let id = VarInt::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
+ let id = VarInt::decode(buf)?;
Ok(Self(id))
}
}
impl wire::Encode for StreamId {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- self.0.encode(writer)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.0.encode(buf)
}
}
@@ -272,19 +273,19 @@ pub enum Control {
}
impl wire::Decode for Control {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
- let command = u8::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
+ let command = u8::decode(buf)?;
match command {
CONTROL_OPEN => {
- let stream = StreamId::decode(reader)?;
+ let stream = StreamId::decode(buf)?;
Ok(Control::Open { stream })
}
CONTROL_CLOSE => {
- let stream = StreamId::decode(reader)?;
+ let stream = StreamId::decode(buf)?;
Ok(Control::Close { stream })
}
CONTROL_EOF => {
- let stream = StreamId::decode(reader)?;
+ let stream = StreamId::decode(buf)?;
Ok(Control::Eof { stream })
}
other => Err(wire::Error::InvalidControlMessage(other)),
@@ -293,38 +294,35 @@ impl wire::Decode for Control {
}
impl wire::Encode for Control {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = 0;
-
+ fn encode(&self, buf: &mut impl BufMut) {
match self {
Self::Open { stream: id } => {
- n += CONTROL_OPEN.encode(writer)?;
- n += id.encode(writer)?;
+ CONTROL_OPEN.encode(buf);
+ id.encode(buf);
}
Self::Eof { stream: id } => {
- n += CONTROL_EOF.encode(writer)?;
- n += id.encode(writer)?;
+ CONTROL_EOF.encode(buf);
+ id.encode(buf);
}
Self::Close { stream: id } => {
- n += CONTROL_CLOSE.encode(writer)?;
- n += id.encode(writer)?;
+ CONTROL_CLOSE.encode(buf);
+ id.encode(buf);
}
}
- Ok(n)
}
}
impl<M: wire::Decode> wire::Decode for Frame<M> {
- fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
- let version = Version::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
+ let version = Version::decode(buf)?;
if version.number() != PROTOCOL_VERSION {
return Err(wire::Error::WrongProtocolVersion(version.number()));
}
- let stream = StreamId::decode(reader)?;
+ let stream = StreamId::decode(buf)?;
match stream.kind() {
Ok(StreamKind::Control) => {
- let ctrl = Control::decode(reader)?;
+ let ctrl = Control::decode(buf)?;
let frame = Frame {
version,
stream,
@@ -333,7 +331,7 @@ impl<M: wire::Decode> wire::Decode for Frame<M> {
Ok(frame)
}
Ok(StreamKind::Gossip) => {
- let data = varint::payload::decode(reader)?;
+ let data = varint::payload::decode(buf)?;
let mut cursor = io::Cursor::new(data);
let msg = M::decode(&mut cursor)?;
let frame = Frame {
@@ -348,7 +346,7 @@ impl<M: wire::Decode> wire::Decode for Frame<M> {
Ok(frame)
}
Ok(StreamKind::Git { .. }) => {
- let data = varint::payload::decode(reader)?;
+ let data = varint::payload::decode(buf)?;
Ok(Frame::git(stream, data))
}
Err(n) => Err(wire::Error::InvalidStreamKind(n)),
@@ -357,18 +355,14 @@ impl<M: wire::Decode> wire::Decode for Frame<M> {
}
impl<M: wire::Encode> wire::Encode for Frame<M> {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = 0;
-
- n += self.version.encode(writer)?;
- n += self.stream.encode(writer)?;
- n += match &self.data {
- FrameData::Control(ctrl) => ctrl.encode(writer)?,
- FrameData::Git(data) => varint::payload::encode(data, writer)?,
- FrameData::Gossip(msg) => varint::payload::encode(&wire::serialize(msg), writer)?,
- };
-
- Ok(n)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.version.encode(buf);
+ self.stream.encode(buf);
+ match &self.data {
+ FrameData::Control(ctrl) => ctrl.encode(buf),
+ FrameData::Git(data) => varint::payload::encode(data, buf),
+ FrameData::Gossip(msg) => varint::payload::encode(&wire::serialize(msg), buf),
+ }
}
}
diff --git a/crates/radicle-protocol/src/wire/message.rs b/crates/radicle-protocol/src/wire/message.rs
index bcfc2997..765185b7 100644
--- a/crates/radicle-protocol/src/wire/message.rs
+++ b/crates/radicle-protocol/src/wire/message.rs
@@ -1,6 +1,7 @@
-use std::{io, mem, net};
+use std::{mem, net};
-use byteorder::{NetworkEndian, ReadBytesExt};
+use bytes::Buf;
+use bytes::BufMut;
use cyphernet::addr::{tor, Addr, HostName, NetAddr};
use radicle::crypto::Signature;
use radicle::git::Oid;
@@ -114,32 +115,28 @@ impl TryFrom<u8> for AddressType {
}
impl wire::Encode for AnnouncementMessage {
- fn encode<W: std::io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, std::io::Error> {
+ fn encode(&self, buf: &mut impl BufMut) {
match self {
- Self::Node(ann) => ann.encode(writer),
- Self::Inventory(ann) => ann.encode(writer),
- Self::Refs(ann) => ann.encode(writer),
+ Self::Node(ann) => ann.encode(buf),
+ Self::Inventory(ann) => ann.encode(buf),
+ Self::Refs(ann) => ann.encode(buf),
}
}
}
impl wire::Encode for RefsAnnouncement {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = 0;
-
- n += self.rid.encode(writer)?;
- n += self.refs.encode(writer)?;
- n += self.timestamp.encode(writer)?;
-
- Ok(n)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.rid.encode(buf);
+ self.refs.encode(buf);
+ self.timestamp.encode(buf);
}
}
impl wire::Decode for RefsAnnouncement {
- fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
- let rid = RepoId::decode(reader)?;
- let refs = BoundedVec::<_, REF_REMOTE_LIMIT>::decode(reader)?;
- let timestamp = Timestamp::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
+ let rid = RepoId::decode(buf)?;
+ let refs = BoundedVec::<_, REF_REMOTE_LIMIT>::decode(buf)?;
+ let timestamp = Timestamp::decode(buf)?;
Ok(Self {
rid,
@@ -150,20 +147,16 @@ impl wire::Decode for RefsAnnouncement {
}
impl wire::Encode for InventoryAnnouncement {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = 0;
-
- n += self.inventory.encode(writer)?;
- n += self.timestamp.encode(writer)?;
-
- Ok(n)
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.inventory.encode(buf);
+ self.timestamp.encode(buf);
}
}
impl wire::Decode for InventoryAnnouncement {
- fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
- let inventory = BoundedVec::decode(reader)?;
- let timestamp = Timestamp::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
+ let inventory = BoundedVec::decode(buf)?;
+ let timestamp = Timestamp::decode(buf)?;
Ok(Self {
inventory,
@@ -212,28 +205,25 @@ impl From<&Info> for InfoType {
}
impl wire::Encode for Info {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = 0;
- n += u16::from(InfoType::from(self)).encode(writer)?;
+ fn encode(&self, buf: &mut impl BufMut) {
+ u16::from(InfoType::from(self)).encode(buf);
match self {
Info::RefsAlreadySynced { rid, at } => {
- n += rid.encode(writer)?;
- n += at.encode(writer)?;
+ rid.encode(buf);
+ at.encode(buf);
}
}
-
- Ok(n)
}
}
impl wire::Decode for Info {
- fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
- let info_type = reader.read_u16::<NetworkEndian>()?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
+ let info_type = buf.try_get_u16()?;
match InfoType::try_from(info_type) {
Ok(InfoType::RefsAlreadySynced) => {
- let rid = RepoId::decode(reader)?;
- let at = Oid::decode(reader)?;
+ let rid = RepoId::decode(buf)?;
+ let at = Oid::decode(buf)?;
Ok(Self::RefsAlreadySynced { rid, at })
}
@@ -243,8 +233,8 @@ impl wire::Decode for Info {
}
impl wire::Encode for Message {
- fn encode<W: std::io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, std::io::Error> {
- let mut n = self.type_id().encode(writer)?;
+ fn encode(&self, buf: &mut impl BufMut) {
+ self.type_id().encode(buf);
match self {
Self::Subscribe(Subscribe {
@@ -252,50 +242,42 @@ impl wire::Encode for Message {
since,
until,
}) => {
- n += filter.encode(writer)?;
- n += since.encode(writer)?;
- n += until.encode(writer)?;
+ filter.encode(buf);
+ since.encode(buf);
+ until.encode(buf);
}
Self::Announcement(Announcement {
node,
message,
signature,
}) => {
- n += node.encode(writer)?;
- n += signature.encode(writer)?;
- n += message.encode(writer)?;
+ node.encode(buf);
+ signature.encode(buf);
+ message.encode(buf);
}
Self::Info(info) => {
- n += info.encode(writer)?;
+ info.encode(buf);
}
Self::Ping(Ping { ponglen, zeroes }) => {
- n += ponglen.encode(writer)?;
- n += zeroes.encode(writer)?;
+ ponglen.encode(buf);
+ zeroes.encode(buf);
}
Self::Pong { zeroes } => {
- n += zeroes.encode(writer)?;
+ zeroes.encode(buf);
}
}
-
- if n > wire::Size::MAX as usize {
- return Err(io::Error::new(
- io::ErrorKind::InvalidData,
- "Message exceeds maximum size",
- ));
- }
- Ok(n)
}
}
impl wire::Decode for Message {
- fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
- let type_id = reader.read_u16::<NetworkEndian>()?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
+ let type_id = buf.try_get_u16()?;
match MessageType::try_from(type_id) {
Ok(MessageType::Subscribe) => {
- let filter = Filter::decode(reader)?;
- let since = Timestamp::decode(reader)?;
- let until = Timestamp::decode(reader)?;
+ let filter = Filter::decode(buf)?;
+ let since = Timestamp::decode(buf)?;
+ let until = Timestamp::decode(buf)?;
Ok(Self::Subscribe(Subscribe {
filter,
@@ -304,9 +286,9 @@ impl wire::Decode for Message {
}))
}
Ok(MessageType::NodeAnnouncement) => {
- let node = NodeId::decode(reader)?;
- let signature = Signature::decode(reader)?;
- let message = NodeAnnouncement::decode(reader)?.into();
+ let node = NodeId::decode(buf)?;
+ let signature = Signature::decode(buf)?;
+ let message = NodeAnnouncement::decode(buf)?.into();
Ok(Announcement {
node,
@@ -316,9 +298,9 @@ impl wire::Decode for Message {
.into())
}
Ok(MessageType::InventoryAnnouncement) => {
- let node = NodeId::decode(reader)?;
- let signature = Signature::decode(reader)?;
- let message = InventoryAnnouncement::decode(reader)?.into();
+ let node = NodeId::decode(buf)?;
+ let signature = Signature::decode(buf)?;
+ let message = InventoryAnnouncement::decode(buf)?.into();
Ok(Announcement {
node,
@@ -328,9 +310,9 @@ impl wire::Decode for Message {
.into())
}
Ok(MessageType::RefsAnnouncement) => {
- let node = NodeId::decode(reader)?;
- let signature = Signature::decode(reader)?;
- let message = RefsAnnouncement::decode(reader)?.into();
+ let node = NodeId::decode(buf)?;
+ let signature = Signature::decode(buf)?;
+ let message = RefsAnnouncement::decode(buf)?.into();
Ok(Announcement {
node,
@@ -340,16 +322,16 @@ impl wire::Decode for Message {
.into())
}
Ok(MessageType::Info) => {
- let info = Info::decode(reader)?;
+ let info = Info::decode(buf)?;
Ok(Self::Info(info))
}
Ok(MessageType::Ping) => {
- let ponglen = u16::decode(reader)?;
- let zeroes = ZeroBytes::decode(reader)?;
+ let ponglen = u16::decode(buf)?;
+ let zeroes = ZeroBytes::decode(buf)?;
Ok(Self::Ping(Ping { ponglen, zeroes }))
}
Ok(MessageType::Pong) => {
- let zeroes = ZeroBytes::decode(reader)?;
+ let zeroes = ZeroBytes::decode(buf)?;
Ok(Self::Pong { zeroes })
}
Err(other) => Err(wire::Error::UnknownMessageType(other)),
@@ -358,85 +340,82 @@ impl wire::Decode for Message {
}
impl wire::Encode for Address {
- fn encode<W: std::io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, std::io::Error> {
- let mut n = 0;
-
+ fn encode(&self, buf: &mut impl BufMut) {
match self.host {
HostName::Ip(net::IpAddr::V4(ip)) => {
- n += u8::from(AddressType::Ipv4).encode(writer)?;
- n += ip.octets().encode(writer)?;
+ u8::from(AddressType::Ipv4).encode(buf);
+ ip.octets().encode(buf);
}
HostName::Ip(net::IpAddr::V6(ip)) => {
- n += u8::from(AddressType::Ipv6).encode(writer)?;
- n += ip.octets().encode(writer)?;
+ u8::from(AddressType::Ipv6).encode(buf);
+ ip.octets().encode(buf);
}
HostName::Dns(ref dns) => {
- n += u8::from(AddressType::Dns).encode(writer)?;
- n += dns.encode(writer)?;
+ u8::from(AddressType::Dns).encode(buf);
+ dns.encode(buf);
}
HostName::Tor(addr) => {
- n += u8::from(AddressType::Onion).encode(writer)?;
- n += addr.encode(writer)?;
+ u8::from(AddressType::Onion).encode(buf);
+ addr.encode(buf);
}
_ => {
- return Err(io::ErrorKind::Unsupported.into());
+ unimplemented!(
+ "Encoding not defined for addresses of the same type as the following: {:?}",
+ self.host
+ );
}
}
- n += self.port().encode(writer)?;
-
- Ok(n)
+ self.port().encode(buf);
}
}
impl wire::Decode for Address {
- fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
- let addrtype = reader.read_u8()?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
+ let addrtype = buf.try_get_u8()?;
+
let host = match AddressType::try_from(addrtype) {
Ok(AddressType::Ipv4) => {
- let octets: [u8; 4] = wire::Decode::decode(reader)?;
+ let octets: [u8; 4] = wire::Decode::decode(buf)?;
let ip = net::Ipv4Addr::from(octets);
HostName::Ip(net::IpAddr::V4(ip))
}
Ok(AddressType::Ipv6) => {
- let octets: [u8; 16] = wire::Decode::decode(reader)?;
+ let octets: [u8; 16] = wire::Decode::decode(buf)?;
let ip = net::Ipv6Addr::from(octets);
HostName::Ip(net::IpAddr::V6(ip))
}
Ok(AddressType::Dns) => {
- let dns: String = wire::Decode::decode(reader)?;
+ let dns: String = wire::Decode::decode(buf)?;
HostName::Dns(dns)
}
Ok(AddressType::Onion) => {
- let onion: tor::OnionAddrV3 = wire::Decode::decode(reader)?;
+ let onion: tor::OnionAddrV3 = wire::Decode::decode(buf)?;
HostName::Tor(onion)
}
Err(other) => return Err(wire::Error::UnknownAddressType(other)),
};
- let port = u16::decode(reader)?;
+ let port = u16::decode(buf)?;
Ok(Self::from(NetAddr { host, port }))
}
}
impl wire::Encode for ZeroBytes {
- fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut n = (self.len() as u16).encode(writer)?;
- for _ in 0..self.len() {
- n += 0u8.encode(writer)?;
- }
- Ok(n)
+ fn encode(&self, buf: &mut impl BufMut) {
+ (self.len() as u16).encode(buf);
+ buf.put_bytes(0u8, self.len());
}
}
impl wire::Decode for ZeroBytes {
- fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
- let zeroes = u16::decode(reader)?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
+ let zeroes = u16::decode(buf)?;
for _ in 0..zeroes {
- _ = u8::decode(reader)?;
+ _ = u8::decode(buf)?;
}
Ok(ZeroBytes::new(zeroes))
}
@@ -508,40 +487,31 @@ mod tests {
#[test]
fn test_pingpong_encode_max_size() {
- let mut buf = Vec::new();
-
- let ping = Message::Ping(Ping {
+ wire::serialize(&Message::Ping(Ping {
ponglen: 0,
zeroes: ZeroBytes::new(Ping::MAX_PING_ZEROES),
- });
- ping.encode(&mut buf)
- .expect("ping should be within max message size");
+ }));
- let pong = Message::Pong {
+ wire::serialize(&Message::Pong {
zeroes: ZeroBytes::new(Ping::MAX_PONG_ZEROES),
- };
- pong.encode(&mut buf)
- .expect("pong should be within max message size");
+ });
}
#[test]
- fn test_pingpong_encode_size_overflow() {
- let ping = Message::Ping(Ping {
+ #[should_panic(expected = "advance out of bounds")]
+ fn test_ping_encode_size_overflow() {
+ wire::serialize(&Message::Ping(Ping {
ponglen: 0,
zeroes: ZeroBytes::new(Ping::MAX_PING_ZEROES + 1),
- });
-
- let mut buf = Vec::new();
- ping.encode(&mut buf)
- .expect_err("ping should exceed max message size");
+ }));
+ }
- let pong = Message::Pong {
+ #[test]
+ #[should_panic(expected = "advance out of bounds")]
+ fn test_pong_encode_size_overflow() {
+ wire::serialize(&Message::Pong {
zeroes: ZeroBytes::new(Ping::MAX_PONG_ZEROES + 1),
- };
-
- let mut buf = Vec::new();
- pong.encode(&mut buf)
- .expect_err("pong should exceed max message size");
+ });
}
#[quickcheck]
@@ -558,7 +528,7 @@ mod tests {
let mut decoder = Deserializer::<1048576, Message>::new(8);
for item in &items {
- item.encode(&mut decoder).unwrap();
+ item.encode(&mut decoder);
}
for item in items {
assert_eq!(decoder.next().unwrap().unwrap(), item);
@@ -570,12 +540,24 @@ mod tests {
.quickcheck(property as fn(items: Vec<Message>));
}
- #[quickcheck]
- fn prop_zero_bytes_encode_decode(zeroes: ZeroBytes) {
- assert_eq!(
- wire::deserialize::<ZeroBytes>(&wire::serialize(&zeroes)).unwrap(),
- zeroes
- );
+ #[test]
+ fn prop_zero_bytes_encode_decode() {
+ fn property(zeroes: wire::Size) {
+ if zeroes > Ping::MAX_PING_ZEROES {
+ return;
+ }
+
+ let zeroes = ZeroBytes::new(zeroes);
+
+ assert_eq!(
+ wire::deserialize::<ZeroBytes>(&wire::serialize(&zeroes)).unwrap(),
+ zeroes
+ );
+ }
+
+ qcheck::QuickCheck::new()
+ .gen(qcheck::Gen::new(16))
+ .quickcheck(property as fn(zeroes: wire::Size));
}
#[quickcheck]
diff --git a/crates/radicle-protocol/src/wire/varint.rs b/crates/radicle-protocol/src/wire/varint.rs
index 0a27e863..eaf3daa4 100644
--- a/crates/radicle-protocol/src/wire/varint.rs
+++ b/crates/radicle-protocol/src/wire/varint.rs
@@ -3,9 +3,9 @@
// This implementation is largely based on the `quinn` crate.
// Copyright (c) 2018 The quinn developers.
-use std::{fmt, io, ops};
+use std::{fmt, ops};
-use byteorder::ReadBytesExt;
+use bytes::{Buf, BufMut};
use thiserror::Error;
use crate::wire;
@@ -44,6 +44,10 @@ impl VarInt {
Err(BoundsExceeded)
}
}
+
+ pub fn new_unchecked(x: u64) -> Self {
+ Self(x)
+ }
}
impl ops::Deref for VarInt {
@@ -98,27 +102,27 @@ impl fmt::Display for VarInt {
pub struct BoundsExceeded;
impl Decode for VarInt {
- fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, wire::Error> {
- let mut buf = [0; 8];
- buf[0] = r.read_u8()?;
+ fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
+ let mut tmp = [0; 8];
+ tmp[0] = buf.try_get_u8()?;
// Integer length.
- let tag = buf[0] >> 6;
- buf[0] &= 0b0011_1111;
+ let tag = tmp[0] >> 6;
+ tmp[0] &= 0b0011_1111;
let x = match tag {
- 0b00 => u64::from(buf[0]),
+ 0b00 => u64::from(tmp[0]),
0b01 => {
- r.read_exact(&mut buf[1..2])?;
- u64::from(u16::from_be_bytes([buf[0], buf[1]]))
+ buf.try_copy_to_slice(&mut tmp[1..2])?;
+ u64::from(u16::from_be_bytes([tmp[0], tmp[1]]))
}
0b10 => {
- r.read_exact(&mut buf[1..4])?;
- u64::from(u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]))
+ buf.try_copy_to_slice(&mut tmp[1..4])?;
+ u64::from(u32::from_be_bytes([tmp[0], tmp[1], tmp[2], tmp[3]]))
}
0b11 => {
- r.read_exact(&mut buf[1..8])?;
- u64::from_be_bytes(buf)
+ buf.try_copy_to_slice(&mut tmp[1..8])?;
+ u64::from_be_bytes(tmp)
}
// SAFETY: It should be obvious that we can't have any other bit pattern
// than the above, since all other bits are zeroed.
@@ -129,7 +133,7 @@ impl Decode for VarInt {
}
impl Encode for VarInt {
- fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> io::Result<usize> {
+ fn encode(&self, w: &mut impl BufMut) {
let x: u64 = self.0;
if x < 2u64.pow(6) {
@@ -151,25 +155,19 @@ pub mod payload {
use super::*;
/// Encode varint-prefixed data payload.
- pub fn encode<W: io::Write + ?Sized>(payload: &[u8], writer: &mut W) -> io::Result<usize> {
- let mut n = 0;
+ pub fn encode(payload: &[u8], buf: &mut impl BufMut) {
let len = payload.len();
- let varint =
- VarInt::new(len as u64).map_err(|_| io::Error::from(io::ErrorKind::InvalidInput))?;
-
- n += varint.encode(writer)?; // The length of the payload length.
- n += len; // The length of the data payload itself.
-
- writer.write_all(payload)?;
+ let varint = VarInt::new_unchecked(len as u64);
- Ok(n)
+ varint.encode(buf); // The length of the payload length.
+ buf.put_slice(payload);
}
/// Decode varint-prefixed data payload.
- pub fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Vec<u8>, wire::Error> {
- let size = VarInt::decode(reader)?;
+ pub fn decode(buf: &mut impl Buf) -> Result<Vec<u8>, wire::Error> {
+ let size = VarInt::decode(buf)?;
let mut data = vec![0; *size as usize];
- reader.read_exact(&mut data[..])?;
+ buf.try_copy_to_slice(&mut data[..])?;
Ok(data)
}
diff --git a/crates/radicle-ssh/Cargo.toml b/crates/radicle-ssh/Cargo.toml
index b16fe402..a5a9d60f 100644
--- a/crates/radicle-ssh/Cargo.toml
+++ b/crates/radicle-ssh/Cargo.toml
@@ -14,7 +14,7 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-byteorder = { workspace = true }
+byteorder = "1.4"
log = { workspace = true }
thiserror = { workspace = true }
zeroize = { workspace = true }
Exit code: 0
shell: 'cargo --version rustc --version cargo fmt --check cargo clippy --all-targets --workspace -- --deny warnings cargo build --all-targets --workspace cargo doc --workspace --no-deps cargo test --workspace --no-fail-fast '
Commands:
$ podman run --name 31de768b-be18-4ab7-9637-0c3f74b4908e -v /opt/radcis/ci.rad.levitte.org/cci/state/31de768b-be18-4ab7-9637-0c3f74b4908e/s:/31de768b-be18-4ab7-9637-0c3f74b4908e/s:ro -v /opt/radcis/ci.rad.levitte.org/cci/state/31de768b-be18-4ab7-9637-0c3f74b4908e/w:/31de768b-be18-4ab7-9637-0c3f74b4908e/w -w /31de768b-be18-4ab7-9637-0c3f74b4908e/w -v /opt/radcis/ci.rad.levitte.org/.radicle:/${id}/.radicle:ro -e RAD_HOME=/${id}/.radicle rust:bookworm bash /31de768b-be18-4ab7-9637-0c3f74b4908e/s/script.sh
+ cargo --version
info: syncing channel updates for '1.85-x86_64-unknown-linux-gnu'
info: latest update on 2025-03-18, rust version 1.85.1 (4eb161250 2025-03-15)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
info: downloading component 'rust-src'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
info: installing component 'rust-src'
info: installing component 'rust-std'
info: installing component 'rustc'
info: installing component 'rustfmt'
cargo 1.85.1 (d73d2caf9 2024-12-31)
+ rustc --version
rustc 1.85.1 (4eb161250 2025-03-15)
+ cargo fmt --check
+ cargo clippy --all-targets --workspace -- --deny warnings
Updating crates.io index
Downloading crates ...
Downloaded derive_more v2.0.1
Downloaded thiserror v2.0.12
Downloaded aho-corasick v1.1.3
Downloaded radicle-surf v0.22.0
Downloaded phf v0.11.3
Downloaded p384 v0.13.0
Downloaded regex v1.11.1
Downloaded referencing v0.30.0
Downloaded ssh-cipher v0.2.0
Downloaded radicle-git-ext v0.8.1
Downloaded sha1_smol v1.0.0
Downloaded cpufeatures v0.2.12
Downloaded cc v1.2.2
Downloaded streaming-iterator v0.1.9
Downloaded sem_safe v0.2.0
Downloaded smallvec v1.13.2
Downloaded socks5-client v0.4.1
Downloaded sqlite3-sys v0.15.2
Downloaded stable_deref_trait v1.2.0
Downloaded sqlite v0.32.0
Downloaded thiserror-impl v1.0.69
Downloaded tar v0.4.40
Downloaded ssh-key v0.6.6
Downloaded signature v2.2.0
Downloaded inout v0.1.3
Downloaded fastrand v2.1.0
Downloaded ghash v0.5.1
Downloaded anstyle v1.0.6
Downloaded tinyvec_macros v0.1.1
Downloaded spki v0.7.3
Downloaded siphasher v0.3.11
Downloaded tinystr v0.7.6
Downloaded thiserror-impl v2.0.12
Downloaded thiserror v1.0.69
Downloaded subtle v2.5.0
Downloaded num-cmp v0.1.0
Downloaded ff v0.13.0
Downloaded ecdsa v0.16.9
Downloaded io-reactor v0.5.2
Downloaded timeago v0.4.2
Downloaded tree-sitter-json v0.24.8
Downloaded anyhow v1.0.82
Downloaded gix-config-value v0.14.12
Downloaded tree-sitter-language v0.1.2
Downloaded serde v1.0.219
Downloaded num-integer v0.1.46
Downloaded gix-commitgraph v0.25.1
Downloaded gix-chunk v0.4.11
Downloaded idna_adapter v1.2.0
Downloaded unicode-width v0.1.11
Downloaded elliptic-curve v0.13.8
Downloaded memmap2 v0.9.4
Downloaded writeable v0.5.5
Downloaded newline-converter v0.3.0
Downloaded tree-sitter-highlight v0.24.4
Downloaded unicode-segmentation v1.11.0
Downloaded fraction v0.15.3
Downloaded gix-packetline v0.18.4
Downloaded gix-protocol v0.47.0
Downloaded indexmap v2.2.6
Downloaded yoke-derive v0.7.5
Downloaded localtime v1.3.1
Downloaded icu_provider_macros v1.5.0
Downloaded yansi v0.5.1
Downloaded gix-trace v0.1.12
Downloaded uuid-simd v0.8.0
Downloaded utf8parse v0.2.1
Downloaded utf8_iter v1.0.4
Downloaded lock_api v0.4.11
Downloaded outref v0.5.2
Downloaded gix-odb v0.66.0
Downloaded write16 v1.0.0
Downloaded tree-sitter-toml-ng v0.6.0
Downloaded gix-traverse v0.43.1
Downloaded multibase v0.9.1
Downloaded home v0.5.9
Downloaded gix-negotiate v0.17.0
Downloaded typeid v1.0.3
Downloaded gix-utils v0.1.14
Downloaded gix-revwalk v0.17.0
Downloaded gix-object v0.46.1
Downloaded zerovec-derive v0.10.3
Downloaded group v0.13.0
Downloaded gix-sec v0.10.12
Downloaded gix-tempfile v15.0.0
Downloaded gix-refspec v0.27.0
Downloaded gix-shallow v0.1.0
Downloaded maybe-async v0.2.10
Downloaded gix-revision v0.31.1
Downloaded gix-validate v0.9.4
Downloaded once_cell v1.21.3
Downloaded gix-lock v15.0.1
Downloaded utf16_iter v1.0.5
Downloaded zeroize v1.7.0
Downloaded memchr v2.7.2
Downloaded num v0.4.3
Downloaded icu_properties v1.5.1
Downloaded yoke v0.7.5
Downloaded winnow v0.6.26
Downloaded num-rational v0.4.2
Downloaded tree-sitter-c v0.23.2
Downloaded unicode-ident v1.0.12
Downloaded url v2.5.4
Downloaded idna v1.0.3
Downloaded mio v1.0.4
Downloaded icu_properties_data v1.5.1
Downloaded mio v0.8.11
Downloaded zerovec v0.10.4
Downloaded zerocopy v0.7.35
Downloaded rustix v1.0.7
Downloaded tree-sitter-md v0.3.2
Downloaded rustix v0.38.34
Downloaded tree-sitter-bash v0.23.3
Downloaded regex-syntax v0.8.5
Downloaded unicode-normalization v0.1.23
Downloaded tree-sitter-python v0.23.4
Downloaded tree-sitter-rust v0.23.2
Downloaded num-bigint v0.4.6
Downloaded jsonschema v0.30.0
Downloaded icu_collections v1.5.0
Downloaded libc v0.2.174
Downloaded tree-sitter-go v0.23.4
Downloaded netservices v0.8.0
Downloaded hashbrown v0.14.3
Downloaded bstr v1.9.1
Downloaded tree-sitter-ruby v0.23.1
Downloaded litemap v0.7.5
Downloaded sha3 v0.10.8
Downloaded icu_normalizer v1.5.0
Downloaded icu_locid_transform_data v1.5.1
Downloaded icu_locid v1.5.0
Downloaded jiff v0.2.1
Downloaded iana-time-zone v0.1.60
Downloaded tree-sitter-typescript v0.23.2
Downloaded log v0.4.21
Downloaded num-traits v0.2.19
Downloaded icu_normalizer_data v1.5.1
Downloaded num-iter v0.1.45
Downloaded litrs v0.4.1
Downloaded p256 v0.13.2
Downloaded miniz_oxide v0.8.8
Downloaded icu_locid_transform v1.5.0
Downloaded git2 v0.19.0
Downloaded tree-sitter-css v0.23.1
Downloaded gix-ref v0.49.1
Downloaded normalize-line-endings v0.3.0
Downloaded hmac v0.12.1
Downloaded typenum v1.17.0
Downloaded gix-hashtable v0.6.0
Downloaded uuid v1.16.0
Downloaded universal-hash v0.5.1
Downloaded unicode-display-width v0.3.0
Downloaded gix-url v0.28.2
Downloaded zerofrom-derive v0.1.6
Downloaded vcpkg v0.2.15
Downloaded syn v1.0.109
Downloaded opaque-debug v0.3.1
Downloaded gix-transport v0.44.0
Downloaded nonempty v0.9.0
Downloaded noise-framework v0.4.0
Downloaded tree-sitter v0.24.4
Downloaded zerofrom v0.1.6
Downloaded gix-diff v0.49.0
Downloaded gix-path v0.10.15
Downloaded gix-pack v0.56.0
Downloaded keccak v0.1.5
Downloaded icu_provider v1.5.0
Downloaded syn v2.0.89
Downloaded gix-quote v0.4.15
Downloaded tree-sitter-html v0.23.2
Downloaded lexopt v0.3.0
Downloaded lazy_static v1.5.0
Downloaded linux-raw-sys v0.4.13
Downloaded jobserver v0.1.31
Downloaded inquire v0.7.5
Downloaded gix-hash v0.15.1
Downloaded gix-features v0.39.1
Downloaded gix-credentials v0.26.0
Downloaded gix-prompt v0.9.1
Downloaded gix-date v0.9.4
Downloaded num-bigint-dig v0.8.4
Downloaded libm v0.2.8
Downloaded emojis v0.6.4
Downloaded cyphernet v0.5.2
Downloaded crossterm v0.29.0
Downloaded chrono v0.4.38
Downloaded xattr v1.3.1
Downloaded gix-fs v0.12.1
Downloaded serde_json v1.0.140
Downloaded gix-command v0.4.1
Downloaded libgit2-sys v0.17.0+1.8.1
Downloaded vsimd v0.8.0
Downloaded git-ref-format-macro v0.3.1
Downloaded walkdir v2.5.0
Downloaded version_check v0.9.4
Downloaded der v0.7.9
Downloaded crypto-bigint v0.5.5
Downloaded num-complex v0.4.6
Downloaded flate2 v1.1.1
Downloaded gix-actor v0.33.2
Downloaded pretty_assertions v1.4.0
Downloaded fancy-regex v0.14.0
Downloaded chacha20poly1305 v0.10.1
Downloaded base64 v0.22.1
Downloaded crossterm v0.25.0
Downloaded derive_more-impl v2.0.1
Downloaded base64 v0.21.7
Downloaded rsa v0.9.6
Downloaded nonempty v0.5.0
Downloaded bytes v1.10.1
Downloaded schemars v1.0.4
Downloaded fluent-uri v0.3.2
Downloaded base-x v0.2.11
Downloaded anstream v0.6.13
Downloaded tinyvec v1.6.0
Downloaded schemars_derive v1.0.4
Downloaded pkcs8 v0.10.2
Downloaded linux-raw-sys v0.9.4
Downloaded pkcs1 v0.7.5
Downloaded sqlite3-src v0.5.1
Downloaded ec25519 v0.1.0
Downloaded bit-set v0.8.0
Downloaded anstyle-parse v0.2.3
Downloaded itoa v1.0.11
Downloaded ppv-lite86 v0.2.17
Downloaded shell-words v1.1.0
Downloaded popol v3.0.0
Downloaded pkg-config v0.3.30
Downloaded getrandom v0.2.15
Downloaded form_urlencoded v1.2.1
Downloaded erased-serde v0.4.6
Downloaded displaydoc v0.2.5
Downloaded ctr v0.9.2
Downloaded bytecount v0.6.8
Downloaded base64 v0.13.1
Downloaded snapbox-macros v0.3.8
Downloaded serde_derive v1.0.219
Downloaded sec1 v0.7.3
Downloaded amplify_num v0.5.2
Downloaded filetime v0.2.23
Downloaded faster-hex v0.9.0
Downloaded either v1.11.0
Downloaded dyn-clone v1.0.17
Downloaded data-encoding v2.5.0
Downloaded cypheraddr v0.4.0
Downloaded bloomy v1.2.0
Downloaded anstyle-query v1.0.2
Downloaded ryu v1.0.17
Downloaded similar v2.5.0
Downloaded polyval v0.6.2
Downloaded poly1305 v0.8.0
Downloaded email_address v0.2.9
Downloaded ed25519 v1.5.3
Downloaded document-features v0.2.11
Downloaded cyphergraphy v0.3.0
Downloaded block-padding v0.3.3
Downloaded amplify_syn v2.0.1
Downloaded escargot v0.5.10
Downloaded signal-hook-registry v1.4.5
Downloaded rfc6979 v0.4.0
Downloaded git-ref-format v0.3.1
Downloaded generic-array v0.14.7
Downloaded signature v1.6.4
Downloaded shlex v1.3.0
Downloaded scrypt v0.11.0
Downloaded salsa20 v0.10.2
Downloaded equivalent v1.0.1
Downloaded diff v0.1.13
Downloaded data-encoding-macro v0.1.14
Downloaded socket2 v0.5.7
Downloaded snapbox v0.4.17
Downloaded sha2 v0.10.8
Downloaded scopeguard v1.2.0
Downloaded prodash v29.0.2
Downloaded crypto-common v0.1.6
Downloaded cipher v0.4.4
Downloaded byteorder v1.5.0
Downloaded bcrypt-pbkdf v0.10.0
Downloaded base16ct v0.2.0
Downloaded synstructure v0.13.1
Downloaded spin v0.9.8
Downloaded serde_derive_internals v0.29.1
Downloaded bit-vec v0.8.0
Downloaded base64ct v1.6.0
Downloaded ssh-encoding v0.2.0
Downloaded siphasher v1.0.1
Downloaded errno v0.3.13
Downloaded cbc v0.1.2
Downloaded signals_receipts v0.2.0
Downloaded proc-macro-error-attr v1.0.4
Downloaded bitflags v2.9.1
Downloaded signal-hook-mio v0.2.4
Downloaded serde-untagged v0.1.7
Downloaded ct-codecs v1.1.1
Downloaded colorchoice v1.0.0
Downloaded rand_core v0.6.4
Downloaded borrow-or-share v0.2.2
Downloaded quote v1.0.36
Downloaded pbkdf2 v0.12.2
Downloaded bitflags v1.3.2
Downloaded ref-cast v1.0.24
Downloaded fxhash v0.2.1
Downloaded digest v0.10.7
Downloaded crossbeam-channel v0.5.15
Downloaded const-oid v0.9.6
Downloaded cfg-if v1.0.0
Downloaded autocfg v1.2.0
Downloaded proc-macro2 v1.0.92
Downloaded proc-macro-error v1.0.4
Downloaded libz-sys v1.1.16
Downloaded pem-rfc7468 v0.7.0
Downloaded block-buffer v0.10.4
Downloaded same-file v1.0.6
Downloaded regex-automata v0.4.9
Downloaded radicle-std-ext v0.1.0
Downloaded primeorder v0.13.6
Downloaded percent-encoding v2.3.1
Downloaded crossbeam-utils v0.8.19
Downloaded chacha20 v0.9.1
Downloaded arc-swap v1.7.1
Downloaded ahash v0.8.11
Downloaded ref-cast-impl v1.0.24
Downloaded rand_chacha v0.3.1
Downloaded qcheck-macros v1.0.0
Downloaded qcheck v1.0.0
Downloaded p521 v0.13.3
Downloaded crc32fast v1.4.0
Downloaded convert_case v0.7.1
Downloaded colored v2.1.0
Downloaded bytesize v2.0.1
Downloaded blowfish v0.9.1
Downloaded base32 v0.4.0
Downloaded ascii v1.1.0
Downloaded rand v0.8.5
Downloaded phf_shared v0.11.3
Downloaded aead v0.5.2
Downloaded aes-gcm v0.10.3
Downloaded parking_lot v0.12.3
Downloaded adler2 v2.0.0
Downloaded git-ref-format-core v0.3.1
Downloaded amplify v4.6.0
Downloaded aes v0.8.4
Downloaded tempfile v3.10.1
Downloaded signal-hook v0.3.18
Downloaded parking_lot_core v0.9.9
Downloaded amplify_derive v4.0.0
Downloaded data-encoding-macro-internal v0.1.12
Compiling libc v0.2.174
Compiling proc-macro2 v1.0.92
Compiling unicode-ident v1.0.12
Checking cfg-if v1.0.0
Compiling shlex v1.3.0
Compiling version_check v0.9.4
Checking memchr v2.7.2
Compiling serde v1.0.219
Compiling autocfg v1.2.0
Compiling quote v1.0.36
Checking getrandom v0.2.15
Compiling jobserver v0.1.31
Checking smallvec v1.13.2
Checking aho-corasick v1.1.3
Compiling syn v2.0.89
Compiling cc v1.2.2
Compiling typenum v1.17.0
Checking regex-syntax v0.8.5
Compiling generic-array v0.14.7
Checking log v0.4.21
Checking rand_core v0.6.4
Checking regex-automata v0.4.9
Checking fastrand v2.1.0
Checking crypto-common v0.1.6
Compiling lock_api v0.4.11
Compiling parking_lot_core v0.9.9
Checking bitflags v2.9.1
Checking scopeguard v1.2.0
Checking subtle v2.5.0
Checking stable_deref_trait v1.2.0
Checking parking_lot v0.12.3
Compiling syn v1.0.109
Checking once_cell v1.21.3
Compiling synstructure v0.13.1
Checking tinyvec_macros v0.1.1
Checking tinyvec v1.6.0
Checking zeroize v1.7.0
Checking bstr v1.9.1
Checking unicode-normalization v0.1.23
Checking cpufeatures v0.2.12
Compiling serde_derive v1.0.219
Compiling zerofrom-derive v0.1.6
Compiling yoke-derive v0.7.5
Checking zerofrom v0.1.6
Compiling zerovec-derive v0.10.3
Checking yoke v0.7.5
Compiling displaydoc v0.2.5
Compiling thiserror v2.0.12
Checking zerovec v0.10.4
Compiling crc32fast v1.4.0
Checking litemap v0.7.5
Compiling icu_locid_transform_data v1.5.1
Checking writeable v0.5.5
Checking tinystr v0.7.6
Compiling icu_provider_macros v1.5.0
Compiling thiserror-impl v2.0.12
Checking icu_locid v1.5.0
Checking block-padding v0.3.3
Compiling icu_properties_data v1.5.1
Checking icu_provider v1.5.0
Checking inout v0.1.3
Checking block-buffer v0.10.4
Compiling pkg-config v0.3.30
Compiling icu_normalizer_data v1.5.1
Checking itoa v1.0.11
Checking hashbrown v0.14.3
Checking digest v0.10.7
Checking icu_locid_transform v1.5.0
Checking cipher v0.4.4
Checking icu_collections v1.5.0
Checking utf8_iter v1.0.4
Compiling thiserror v1.0.69
Checking utf16_iter v1.0.5
Checking write16 v1.0.0
Compiling thiserror-impl v1.0.69
Checking icu_properties v1.5.1
Checking percent-encoding v2.3.1
Compiling rustix v0.38.34
Checking linux-raw-sys v0.4.13
Checking sha2 v0.10.8
Checking form_urlencoded v1.2.1
Checking universal-hash v0.5.1
Compiling vcpkg v0.2.15
Checking opaque-debug v0.3.1
Checking icu_normalizer v1.5.0
Compiling amplify_syn v2.0.1
Compiling libz-sys v1.1.16
Checking byteorder v1.5.0
Checking idna_adapter v1.2.0
Checking idna v1.0.3
Checking gix-trace v0.1.12
Checking url v2.5.4
Compiling data-encoding v2.5.0
Compiling amplify_derive v4.0.0
Checking tempfile v3.10.1
Checking amplify_num v0.5.2
Compiling data-encoding-macro-internal v0.1.12
Checking signature v1.6.4
Checking ascii v1.1.0
Checking data-encoding-macro v0.1.14
Checking ed25519 v1.5.3
Checking faster-hex v0.9.0
Compiling libgit2-sys v0.17.0+1.8.1
Checking aead v0.5.2
Compiling num-traits v0.2.19
Compiling proc-macro-error-attr v1.0.4
Checking base-x v0.2.11
Checking ct-codecs v1.1.1
Checking multibase v0.9.1
Checking ec25519 v0.1.0
Checking poly1305 v0.8.0
Checking amplify v4.6.0
Checking chacha20 v0.9.1
Checking gix-utils v0.1.14
Compiling proc-macro-error v1.0.4
Checking adler2 v2.0.0
Checking cyphergraphy v0.3.0
Checking miniz_oxide v0.8.8
Checking gix-hash v0.15.1
Checking keccak v0.1.5
Compiling crossbeam-utils v0.8.19
Checking same-file v1.0.6
Checking sha3 v0.10.8
Checking walkdir v2.5.0
Checking flate2 v1.1.1
Compiling git-ref-format-core v0.3.1
Checking polyval v0.6.2
Checking hmac v0.12.1
Compiling sqlite3-src v0.5.1
Checking prodash v29.0.2
Checking equivalent v1.0.1
Checking base64ct v1.6.0
Checking base32 v0.4.0
Compiling serde_json v1.0.140
Checking ppv-lite86 v0.2.17
Checking sha1_smol v1.0.0
Checking gix-features v0.39.1
Checking cypheraddr v0.4.0
Checking rand_chacha v0.3.1
Checking pem-rfc7468 v0.7.0
Checking indexmap v2.2.6
Checking pbkdf2 v0.12.2
Compiling git-ref-format-macro v0.3.1
Checking ghash v0.5.1
Checking chacha20poly1305 v0.10.1
Checking aes v0.8.4
Checking ctr v0.9.2
Checking ryu v1.0.17
Checking aes-gcm v0.10.3
Checking git-ref-format v0.3.1
Checking crossbeam-channel v0.5.15
Checking noise-framework v0.4.0
Checking ssh-encoding v0.2.0
Checking socks5-client v0.4.1
Checking rand v0.8.5
Checking blowfish v0.9.1
Checking cbc v0.1.2
Checking radicle-std-ext v0.1.0
Checking home v0.5.9
Compiling ref-cast v1.0.24
Checking gix-path v0.10.15
Checking ssh-cipher v0.2.0
Checking bcrypt-pbkdf v0.10.0
Checking cyphernet v0.5.2
Compiling ref-cast-impl v1.0.24
Checking signature v2.2.0
Checking ssh-key v0.6.6
Checking qcheck v1.0.0
Checking radicle-ssh v0.9.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-ssh)
Checking lazy_static v1.5.0
Checking dyn-clone v1.0.17
Compiling typeid v1.0.3
Checking siphasher v1.0.1
Checking nonempty v0.9.0
Compiling serde_derive_internals v0.29.1
Checking radicle-dag v0.10.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-dag)
Checking erased-serde v0.4.6
Checking iana-time-zone v0.1.60
Checking jiff v0.2.1
Compiling schemars_derive v1.0.4
Checking schemars v1.0.4
Checking chrono v0.4.38
Checking gix-date v0.9.4
Checking serde-untagged v0.1.7
Checking colored v2.1.0
Checking localtime v1.3.1
Checking bytesize v2.0.1
Checking winnow v0.6.26
Checking base64 v0.21.7
Checking tree-sitter-language v0.1.2
Checking gix-hashtable v0.6.0
Checking gix-validate v0.9.4
Checking memmap2 v0.9.4
Compiling anyhow v1.0.82
Checking gix-chunk v0.4.11
Checking gix-actor v0.33.2
Checking anstyle-query v1.0.2
Checking gix-commitgraph v0.25.1
Checking gix-object v0.46.1
Checking gix-fs v0.12.1
Checking errno v0.3.13
Checking sem_safe v0.2.0
Checking signals_receipts v0.2.0
Checking gix-revwalk v0.17.0
Checking gix-tempfile v15.0.0
Compiling signal-hook v0.3.18
Checking signal-hook-registry v1.4.5
Checking shell-words v1.1.0
Checking gix-command v0.4.1
Checking radicle-signals v0.11.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-signals)
Checking mio v1.0.4
Checking mio v0.8.11
Compiling tree-sitter v0.24.4
Compiling unicode-segmentation v1.11.0
Compiling convert_case v0.7.1
Checking signal-hook-mio v0.2.4
Checking gix-lock v15.0.1
Checking gix-config-value v0.14.12
Checking gix-url v0.28.2
Checking gix-quote v0.4.15
Checking regex v1.11.1
Checking gix-sec v0.10.12
Compiling rustix v1.0.7
Checking sqlite3-sys v0.15.2
Checking sqlite v0.32.0
Checking gix-prompt v0.9.1
Compiling xattr v1.3.1
Compiling derive_more-impl v2.0.1
Compiling filetime v0.2.23
Checking gix-traverse v0.43.1
Checking gix-revision v0.31.1
Checking gix-diff v0.49.0
Checking gix-packetline v0.18.4
Checking lexopt v0.3.0
Checking linux-raw-sys v0.9.4
Checking utf8parse v0.2.1
Checking bitflags v1.3.2
Compiling litrs v0.4.1
Checking crossterm v0.25.0
Compiling document-features v0.2.11
Checking anstyle-parse v0.2.3
Checking derive_more v2.0.1
Checking gix-transport v0.44.0
Checking gix-pack v0.56.0
Checking gix-refspec v0.27.0
Compiling tar v0.4.40
Checking gix-credentials v0.26.0
Checking newline-converter v0.3.0
Checking gix-shallow v0.1.0
Checking gix-ref v0.49.1
Checking gix-negotiate v0.17.0
Checking fxhash v0.2.1
Compiling maybe-async v0.2.10
Checking colorchoice v1.0.0
Checking anstyle v1.0.6
Checking streaming-iterator v0.1.9
Checking arc-swap v1.7.1
Checking unicode-width v0.1.11
Checking gix-odb v0.66.0
Checking inquire v0.7.5
Checking gix-protocol v0.47.0
Checking anstream v0.6.13
Compiling radicle-surf v0.22.0
Checking crossterm v0.29.0
Checking unicode-display-width v0.3.0
Compiling tree-sitter-typescript v0.23.2
Compiling tree-sitter-md v0.3.2
Compiling tree-sitter-rust v0.23.2
Compiling tree-sitter-ruby v0.23.1
Compiling tree-sitter-go v0.23.4
Compiling tree-sitter-toml-ng v0.6.0
Compiling tree-sitter-bash v0.23.3
Compiling tree-sitter-html v0.23.2
Compiling tree-sitter-json v0.24.8
Compiling tree-sitter-python v0.23.4
Compiling tree-sitter-css v0.23.1
Compiling tree-sitter-c v0.23.2
Checking either v1.11.0
Checking snapbox-macros v0.3.8
Checking salsa20 v0.10.2
Checking siphasher v0.3.11
Checking normalize-line-endings v0.3.0
Compiling radicle-cli v0.14.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cli)
Checking nonempty v0.5.0
Checking similar v2.5.0
Checking base64 v0.13.1
Checking snapbox v0.4.17
Checking bloomy v1.2.0
Checking scrypt v0.11.0
Checking tree-sitter-highlight v0.24.4
Checking popol v3.0.0
Checking bytes v1.10.1
Checking timeago v0.4.2
Checking io-reactor v0.5.2
Checking socket2 v0.5.7
Checking yansi v0.5.1
Checking diff v0.1.13
Compiling radicle-node v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-node)
Checking netservices v0.8.0
Checking pretty_assertions v1.4.0
Checking num-integer v0.1.46
Checking radicle-systemd v0.9.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-systemd)
Compiling escargot v0.5.10
Compiling qcheck-macros v1.0.0
Checking num-bigint v0.4.6
Compiling ahash v0.8.11
Compiling radicle-remote-helper v0.11.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-remote-helper)
Checking num-rational v0.4.2
Checking num-iter v0.1.45
Checking num-complex v0.4.6
Checking zerocopy v0.7.35
Checking borrow-or-share v0.2.2
Checking bit-vec v0.8.0
Checking num v0.4.3
Checking fluent-uri v0.3.2
Checking bit-set v0.8.0
Checking phf_shared v0.11.3
Checking outref v0.5.2
Checking vsimd v0.8.0
Checking uuid v1.16.0
Checking phf v0.11.3
Checking referencing v0.30.0
Checking fancy-regex v0.14.0
Checking uuid-simd v0.8.0
Checking fraction v0.15.3
Checking email_address v0.2.9
Checking num-cmp v0.1.0
Checking bytecount v0.6.8
Checking base64 v0.22.1
Checking emojis v0.6.4
Checking jsonschema v0.30.0
Checking git2 v0.19.0
Checking radicle-git-ext v0.8.1
Checking radicle-term v0.13.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-term)
Checking radicle-crypto v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-crypto)
Checking radicle-cob v0.14.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cob)
Checking radicle v0.16.1 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle)
Checking radicle-fetch v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-fetch)
Checking radicle-cli-test v0.11.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cli-test)
Checking radicle-schemars v0.1.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-schemars)
Checking radicle-protocol v0.1.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-protocol)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 42.20s
+ cargo build --all-targets --workspace
Compiling cfg-if v1.0.0
Compiling libc v0.2.174
Compiling shlex v1.3.0
Compiling memchr v2.7.2
Compiling serde v1.0.219
Compiling smallvec v1.13.2
Compiling aho-corasick v1.1.3
Compiling jobserver v0.1.31
Compiling cc v1.2.2
Compiling getrandom v0.2.15
Compiling regex-syntax v0.8.5
Compiling typenum v1.17.0
Compiling regex-automata v0.4.9
Compiling log v0.4.21
Compiling generic-array v0.14.7
Compiling rand_core v0.6.4
Compiling fastrand v2.1.0
Compiling crypto-common v0.1.6
Compiling bitflags v2.9.1
Compiling scopeguard v1.2.0
Compiling lock_api v0.4.11
Compiling zerofrom v0.1.6
Compiling parking_lot_core v0.9.9
Compiling subtle v2.5.0
Compiling stable_deref_trait v1.2.0
Compiling parking_lot v0.12.3
Compiling yoke v0.7.5
Compiling once_cell v1.21.3
Compiling tinyvec_macros v0.1.1
Compiling tinyvec v1.6.0
Compiling zerovec v0.10.4
Compiling zeroize v1.7.0
Compiling cpufeatures v0.2.12
Compiling litemap v0.7.5
Compiling bstr v1.9.1
Compiling unicode-normalization v0.1.23
Compiling tinystr v0.7.6
Compiling writeable v0.5.5
Compiling block-padding v0.3.3
Compiling thiserror v2.0.12
Compiling icu_locid v1.5.0
Compiling inout v0.1.3
Compiling icu_locid_transform_data v1.5.1
Compiling block-buffer v0.10.4
Compiling itoa v1.0.11
Compiling adler2 v2.0.0
Compiling hashbrown v0.14.3
Compiling miniz_oxide v0.8.8
Compiling icu_provider v1.5.0
Compiling digest v0.10.7
Compiling icu_locid_transform v1.5.0
Compiling cipher v0.4.4
Compiling icu_properties_data v1.5.1
Compiling crc32fast v1.4.0
Compiling icu_collections v1.5.0
Compiling icu_normalizer_data v1.5.1
Compiling write16 v1.0.0
Compiling icu_properties v1.5.1
Compiling utf8_iter v1.0.4
Compiling utf16_iter v1.0.5
Compiling percent-encoding v2.3.1
Compiling linux-raw-sys v0.4.13
Compiling thiserror v1.0.69
Compiling sha2 v0.10.8
Compiling form_urlencoded v1.2.1
Compiling universal-hash v0.5.1
Compiling rustix v0.38.34
Compiling opaque-debug v0.3.1
Compiling libz-sys v1.1.16
Compiling byteorder v1.5.0
Compiling gix-trace v0.1.12
Compiling amplify_num v0.5.2
Compiling icu_normalizer v1.5.0
Compiling idna_adapter v1.2.0
Compiling idna v1.0.3
Compiling url v2.5.4
Compiling tempfile v3.10.1
Compiling ascii v1.1.0
Compiling data-encoding v2.5.0
Compiling signature v1.6.4
Compiling amplify v4.6.0
Compiling libgit2-sys v0.17.0+1.8.1
Compiling data-encoding-macro v0.1.14
Compiling ed25519 v1.5.3
Compiling aead v0.5.2
Compiling faster-hex v0.9.0
Compiling ct-codecs v1.1.1
Compiling base-x v0.2.11
Compiling ec25519 v0.1.0
Compiling multibase v0.9.1
Compiling poly1305 v0.8.0
Compiling chacha20 v0.9.1
Compiling gix-utils v0.1.14
Compiling cyphergraphy v0.3.0
Compiling num-traits v0.2.19
Compiling gix-hash v0.15.1
Compiling keccak v0.1.5
Compiling same-file v1.0.6
Compiling sha3 v0.10.8
Compiling walkdir v2.5.0
Compiling polyval v0.6.2
Compiling git-ref-format-core v0.3.1
Compiling flate2 v1.1.1
Compiling hmac v0.12.1
Compiling sqlite3-src v0.5.1
Compiling prodash v29.0.2
Compiling sha1_smol v1.0.0
Compiling equivalent v1.0.1
Compiling ppv-lite86 v0.2.17
Compiling base32 v0.4.0
Compiling base64ct v1.6.0
Compiling rand_chacha v0.3.1
Compiling pem-rfc7468 v0.7.0
Compiling gix-features v0.39.1
Compiling cypheraddr v0.4.0
Compiling indexmap v2.2.6
Compiling git-ref-format-macro v0.3.1
Compiling pbkdf2 v0.12.2
Compiling ghash v0.5.1
Compiling crossbeam-utils v0.8.19
Compiling chacha20poly1305 v0.10.1
Compiling ctr v0.9.2
Compiling aes v0.8.4
Compiling ryu v1.0.17
Compiling aes-gcm v0.10.3
Compiling serde_json v1.0.140
Compiling git-ref-format v0.3.1
Compiling crossbeam-channel v0.5.15
Compiling noise-framework v0.4.0
Compiling socks5-client v0.4.1
Compiling ssh-encoding v0.2.0
Compiling rand v0.8.5
Compiling blowfish v0.9.1
Compiling cbc v0.1.2
Compiling radicle-std-ext v0.1.0
Compiling home v0.5.9
Compiling gix-path v0.10.15
Compiling ssh-cipher v0.2.0
Compiling bcrypt-pbkdf v0.10.0
Compiling cyphernet v0.5.2
Compiling signature v2.2.0
Compiling ref-cast v1.0.24
Compiling ssh-key v0.6.6
Compiling qcheck v1.0.0
Compiling radicle-ssh v0.9.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-ssh)
Compiling dyn-clone v1.0.17
Compiling lazy_static v1.5.0
Compiling siphasher v1.0.1
Compiling typeid v1.0.3
Compiling radicle-dag v0.10.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-dag)
Compiling nonempty v0.9.0
Compiling erased-serde v0.4.6
Compiling iana-time-zone v0.1.60
Compiling jiff v0.2.1
Compiling serde-untagged v0.1.7
Compiling chrono v0.4.38
Compiling schemars v1.0.4
Compiling gix-date v0.9.4
Compiling colored v2.1.0
Compiling localtime v1.3.1
Compiling bytesize v2.0.1
Compiling winnow v0.6.26
Compiling tree-sitter-language v0.1.2
Compiling base64 v0.21.7
Compiling gix-hashtable v0.6.0
Compiling gix-actor v0.33.2
Compiling gix-validate v0.9.4
Compiling memmap2 v0.9.4
Compiling gix-object v0.46.1
Compiling gix-chunk v0.4.11
Compiling anstyle-query v1.0.2
Compiling gix-commitgraph v0.25.1
Compiling anyhow v1.0.82
Compiling gix-revwalk v0.17.0
Compiling gix-fs v0.12.1
Compiling sqlite3-sys v0.15.2
Compiling sqlite v0.32.0
Compiling sem_safe v0.2.0
Compiling errno v0.3.13
Compiling unicode-segmentation v1.11.0
Compiling signals_receipts v0.2.0
Compiling gix-tempfile v15.0.0
Compiling signal-hook-registry v1.4.5
Compiling shell-words v1.1.0
Compiling gix-command v0.4.1
Compiling signal-hook v0.3.18
Compiling radicle-signals v0.11.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-signals)
Compiling mio v0.8.11
Compiling mio v1.0.4
Compiling tree-sitter v0.24.4
Compiling signal-hook-mio v0.2.4
Compiling convert_case v0.7.1
Compiling gix-lock v15.0.1
Compiling gix-config-value v0.14.12
Compiling gix-url v0.28.2
Compiling gix-quote v0.4.15
Compiling regex v1.11.1
Compiling gix-sec v0.10.12
Compiling xattr v1.3.1
Compiling gix-prompt v0.9.1
Compiling derive_more-impl v2.0.1
Compiling gix-revision v0.31.1
Compiling gix-traverse v0.43.1
Compiling gix-diff v0.49.0
Compiling gix-packetline v0.18.4
Compiling filetime v0.2.23
Compiling lexopt v0.3.0
Compiling utf8parse v0.2.1
Compiling bitflags v1.3.2
Compiling linux-raw-sys v0.9.4
Compiling anstyle-parse v0.2.3
Compiling crossterm v0.25.0
Compiling derive_more v2.0.1
Compiling tar v0.4.40
Compiling rustix v1.0.7
Compiling gix-transport v0.44.0
Compiling gix-pack v0.56.0
Compiling gix-refspec v0.27.0
Compiling gix-credentials v0.26.0
Compiling gix-ref v0.49.1
Compiling gix-shallow v0.1.0
Compiling newline-converter v0.3.0
Compiling gix-negotiate v0.17.0
Compiling fxhash v0.2.1
Compiling colorchoice v1.0.0
Compiling arc-swap v1.7.1
Compiling anstyle v1.0.6
Compiling streaming-iterator v0.1.9
Compiling unicode-width v0.1.11
Compiling inquire v0.7.5
Compiling gix-odb v0.66.0
Compiling anstream v0.6.13
Compiling gix-protocol v0.47.0
Compiling radicle-surf v0.22.0
Compiling crossterm v0.29.0
Compiling unicode-display-width v0.3.0
Compiling tree-sitter-bash v0.23.3
Compiling tree-sitter-css v0.23.1
Compiling tree-sitter-go v0.23.4
Compiling tree-sitter-toml-ng v0.6.0
Compiling tree-sitter-json v0.24.8
Compiling tree-sitter-html v0.23.2
Compiling tree-sitter-c v0.23.2
Compiling tree-sitter-md v0.3.2
Compiling tree-sitter-ruby v0.23.1
Compiling tree-sitter-python v0.23.4
Compiling tree-sitter-rust v0.23.2
Compiling tree-sitter-typescript v0.23.2
Compiling either v1.11.0
Compiling snapbox-macros v0.3.8
Compiling salsa20 v0.10.2
Compiling normalize-line-endings v0.3.0
Compiling nonempty v0.5.0
Compiling similar v2.5.0
Compiling radicle-cli v0.14.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cli)
Compiling siphasher v0.3.11
Compiling base64 v0.13.1
Compiling bloomy v1.2.0
Compiling snapbox v0.4.17
Compiling scrypt v0.11.0
Compiling tree-sitter-highlight v0.24.4
Compiling popol v3.0.0
Compiling bytes v1.10.1
Compiling timeago v0.4.2
Compiling io-reactor v0.5.2
Compiling socket2 v0.5.7
Compiling radicle-node v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-node)
Compiling diff v0.1.13
Compiling yansi v0.5.1
Compiling netservices v0.8.0
Compiling num-integer v0.1.46
Compiling pretty_assertions v1.4.0
Compiling radicle-systemd v0.9.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-systemd)
Compiling escargot v0.5.10
Compiling num-bigint v0.4.6
Compiling radicle-remote-helper v0.11.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-remote-helper)
Compiling num-iter v0.1.45
Compiling num-complex v0.4.6
Compiling num-rational v0.4.2
Compiling borrow-or-share v0.2.2
Compiling zerocopy v0.7.35
Compiling bit-vec v0.8.0
Compiling bit-set v0.8.0
Compiling ahash v0.8.11
Compiling fluent-uri v0.3.2
Compiling num v0.4.3
Compiling phf_shared v0.11.3
Compiling vsimd v0.8.0
Compiling outref v0.5.2
Compiling uuid v1.16.0
Compiling referencing v0.30.0
Compiling uuid-simd v0.8.0
Compiling phf v0.11.3
Compiling fraction v0.15.3
Compiling fancy-regex v0.14.0
Compiling email_address v0.2.9
Compiling base64 v0.22.1
Compiling bytecount v0.6.8
Compiling num-cmp v0.1.0
Compiling emojis v0.6.4
Compiling jsonschema v0.30.0
Compiling git2 v0.19.0
Compiling radicle-git-ext v0.8.1
Compiling radicle-term v0.13.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-term)
Compiling radicle-crypto v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-crypto)
Compiling radicle-cob v0.14.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cob)
Compiling radicle v0.16.1 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle)
Compiling radicle-fetch v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-fetch)
Compiling radicle-protocol v0.1.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-protocol)
Compiling radicle-cli-test v0.11.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cli-test)
Compiling radicle-schemars v0.1.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-schemars)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 04s
+ cargo doc --workspace --no-deps
Checking regex-automata v0.4.9
Compiling syn v1.0.109
Checking idna v1.0.3
Checking radicle-ssh v0.9.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-ssh)
Compiling num-traits v0.2.19
Checking url v2.5.4
Checking git2 v0.19.0
Checking radicle-dag v0.10.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-dag)
Compiling amplify_syn v2.0.1
Checking bstr v1.9.1
Compiling proc-macro-error v1.0.4
Checking git-ref-format-core v0.3.1
Compiling amplify_derive v4.0.0
Compiling data-encoding-macro-internal v0.1.12
Compiling git-ref-format-macro v0.3.1
Checking gix-path v0.10.15
Checking gix-date v0.9.4
Checking git-ref-format v0.3.1
Checking data-encoding-macro v0.1.14
Checking gix-actor v0.33.2
Checking radicle-git-ext v0.8.1
Checking multibase v0.9.1
Checking gix-validate v0.9.4
Checking chrono v0.4.38
Checking gix-commitgraph v0.25.1
Checking gix-object v0.46.1
Checking gix-command v0.4.1
Checking radicle-signals v0.11.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-signals)
Checking regex v1.11.1
Checking amplify v4.6.0
Checking gix-config-value v0.14.12
Checking gix-revwalk v0.17.0
Checking cyphergraphy v0.3.0
Checking tree-sitter v0.24.4
Checking gix-url v0.28.2
Checking gix-quote v0.4.15
Checking gix-prompt v0.9.1
Checking cypheraddr v0.4.0
Checking noise-framework v0.4.0
Checking gix-revision v0.31.1
Checking gix-traverse v0.43.1
Checking socks5-client v0.4.1
Checking gix-diff v0.49.0
Checking cyphernet v0.5.2
Checking gix-packetline v0.18.4
Checking radicle-surf v0.22.0
Checking radicle-crypto v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-crypto)
Checking gix-pack v0.56.0
Checking gix-transport v0.44.0
Checking radicle-cob v0.14.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cob)
Compiling radicle-cli v0.14.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cli)
Checking gix-refspec v0.27.0
Checking tree-sitter-toml-ng v0.6.0
Checking tree-sitter-highlight v0.24.4
Checking gix-credentials v0.26.0
Checking gix-negotiate v0.17.0
Checking radicle v0.16.1 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle)
Checking gix-ref v0.49.1
Checking gix-shallow v0.1.0
Checking radicle-term v0.13.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-term)
Checking gix-odb v0.66.0
Checking io-reactor v0.5.2
Compiling radicle-node v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-node)
Checking netservices v0.8.0
Checking gix-protocol v0.47.0
Checking radicle-systemd v0.9.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-systemd)
Documenting radicle v0.16.1 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle)
Documenting radicle-cob v0.14.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cob)
Documenting radicle-crypto v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-crypto)
Documenting radicle-term v0.13.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-term)
Documenting radicle-signals v0.11.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-signals)
Documenting radicle-ssh v0.9.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-ssh)
Documenting radicle-dag v0.10.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-dag)
Documenting radicle-systemd v0.9.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-systemd)
Checking radicle-fetch v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-fetch)
Documenting radicle-cli v0.14.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cli)
Documenting radicle-cli-test v0.11.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cli-test)
Documenting radicle-fetch v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-fetch)
Checking radicle-protocol v0.1.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-protocol)
Documenting radicle-protocol v0.1.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-protocol)
Documenting radicle-schemars v0.1.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-schemars)
Documenting radicle-node v0.12.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-node)
Checking radicle-remote-helper v0.11.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-remote-helper)
warning: unresolved link to `T`
--> crates/radicle-protocol/src/wire/frame.rs:192:94
|
192 | /// | Stream ID |TTT|I| Stream ID with Stream [T]ype and [I]nitiator bits
| ^ no item named `T` in scope
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
= note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
warning: unresolved link to `I`
--> crates/radicle-protocol/src/wire/frame.rs:192:105
|
192 | /// | Stream ID |TTT|I| Stream ID with Stream [T]ype and [I]nitiator bits
| ^ no item named `I` in scope
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
Documenting radicle-remote-helper v0.11.0 (/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-remote-helper)
warning: `radicle-protocol` (lib doc) generated 2 warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 9.80s
Generated /31de768b-be18-4ab7-9637-0c3f74b4908e/w/target/doc/radicle/index.html and 16 other files
+ cargo test --workspace --no-fail-fast
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.20s
Running unittests src/lib.rs (target/debug/deps/radicle-3fdf443a22b4fc3b)
running 194 tests
test canonical::formatter::test::ascii_control_characters ... ok
test canonical::formatter::test::securesystemslib_asserts ... ok
test canonical::formatter::test::ordered_nested_object ... ok
test cob::cache::migrations::_2::tests::test_patch_json_deserialization ... ok
test cob::common::test::test_color ... ok
test cob::common::test::test_emojis ... ok
test cob::cache::migrations::_2::tests::test_migration_2 ... ok
test cob::cache::tests::test_check_version ... ok
test cob::cache::tests::test_migrate_to ... ok
test cob::identity::test::prop_json_eq_str ... ok
test cob::identity::test::test_identity_redact_revision ... ok
test cob::identity::test::test_identity_update_rejected ... ok
test cob::identity::test::test_identity_remove_delegate_concurrent ... ok
test cob::identity::test::test_identity_reject_concurrent ... ok
test cob::identity::test::test_identity_updates ... ok
test cob::issue::cache::tests::test_counts ... ok
test cob::issue::cache::tests::test_get ... ok
test cob::issue::cache::tests::test_is_empty ... ok
test cob::issue::cache::tests::test_list ... ok
test cob::issue::cache::tests::test_list_by_status ... ok
test cob::issue::cache::tests::test_remove ... ok
test cob::identity::test::test_identity_updates_concurrent ... ok
test cob::identity::test::test_valid_identity ... ok
test cob::issue::test::test_embeds_edit ... ok
test cob::identity::test::test_identity_updates_concurrent_outdated ... ok
test cob::issue::test::test_embeds ... ok
test cob::issue::test::test_invalid_tx ... ok
test cob::issue::test::test_invalid_actions ... ok
test cob::issue::test::test_invalid_cob ... ok
test cob::issue::test::test_invalid_tx_reference ... ok
test cob::issue::test::test_issue_all ... ok
test cob::issue::test::test_issue_comment ... ok
test cob::issue::test::test_issue_create_and_assign ... ok
test cob::issue::test::test_concurrency ... ok
test cob::issue::test::test_issue_comment_redact ... ok
test cob::issue::test::test_issue_create_and_change_state ... ok
test cob::issue::test::test_issue_create_and_reassign ... ok
test cob::issue::test::test_issue_create_and_get ... ok
test cob::issue::test::test_issue_create_and_unassign ... ok
test cob::issue::test::test_issue_edit ... ok
test cob::issue::test::test_issue_edit_description ... ok
test cob::issue::test::test_issue_multilines ... ok
test cob::issue::test::test_issue_state_serde ... ok
test cob::issue::test::test_ordering ... ok
test cob::patch::actions::test::test_review_edit ... ok
test cob::issue::test::test_issue_label ... ok
test cob::issue::test::test_issue_react ... ok
test cob::issue::test::test_issue_reply ... ok
test cob::patch::cache::tests::test_is_empty ... ok
test cob::patch::cache::tests::test_get ... ok
test cob::patch::cache::tests::test_list_by_status ... ok
test cob::patch::cache::tests::test_list ... ok
test cob::patch::encoding::review::test::test_review_deserialize_summary_migration_null_summary ... ok
test cob::patch::encoding::review::test::test_review_deserialize_summary_migration_with_summary ... ok
test cob::patch::encoding::review::test::test_review_deserialize_summary_migration_without_summary ... ok
test cob::patch::encoding::review::test::test_review_deserialize_summary_v2 ... ok
test cob::patch::encoding::review::test::test_review_summary ... ok
test cob::patch::test::test_json ... ok
test cob::patch::test::test_json_serialization ... ok
test cob::patch::cache::tests::test_remove ... ok
test cob::patch::test::test_patch_discussion ... ok
test cob::patch::cache::tests::test_counts ... ok
test cob::patch::test::test_patch_merge ... ok
test cob::patch::test::test_patch_create_and_get ... ok
test cob::patch::test::test_patch_redact ... ok
test cob::patch::test::test_patch_review_comment ... ok
test cob::patch::test::test_patch_review ... ok
test cob::patch::cache::tests::test_find_by_revision ... ok
test cob::patch::test::test_patch_review_edit ... ok
test cob::patch::test::test_patch_review_duplicate ... ok
test cob::patch::test::test_patch_review_remove_summary ... ok
test cob::patch::test::test_reactions_json_serialization ... ok
test cob::patch::test::test_revision_edit_redact ... ok
test cob::patch::test::test_revision_reaction ... ok
test cob::patch::test::test_revision_review_merge_redacted ... ok
test cob::patch::test::test_patch_review_edit_comment ... ok
test cob::thread::tests::test_comment_edit_missing ... ok
test cob::thread::tests::test_comment_edit_redacted ... ok
test cob::thread::tests::test_comment_redact_missing ... ok
test cob::thread::tests::test_duplicate_comments ... ok
test cob::thread::tests::test_edit_comment ... ok
test cob::thread::tests::test_redact_comment ... ok
test cob::patch::test::test_patch_review_revision_redact ... ok
test cob::thread::tests::test_timeline ... ok
test git::canonical::tests::test_quorum_merges ... ok
test git::canonical::tests::test_quorum ... ok
test git::test::test_version_from_str ... ok
test git::test::test_version_ord ... ok
test identity::did::test::test_did_encode_decode ... ok
test identity::did::test::test_did_vectors ... ok
test identity::doc::id::test::prop_from_str ... ok
test cob::patch::test::test_patch_update ... ok
test identity::doc::test::test_canonical_doc ... ok
test git::canonical::tests::test_quorum_properties ... ok
test identity::doc::test::test_duplicate_dids ... ok
test identity::doc::test::test_future_version_error ... ok
test identity::doc::test::test_is_valid_version ... ok
test identity::doc::test::test_canonical_example ... ok
test identity::doc::test::test_not_found ... ok
test identity::doc::test::test_parse_version ... ok
test identity::doc::test::test_visibility_json ... ok
test identity::doc::test::test_max_delegates ... ok
test identity::project::test::test_project_name ... ok
test node::address::store::test::test_alias ... ok
test node::address::store::test::test_disconnected ... ok
test node::address::store::test::test_disconnected_ban ... ok
test node::address::store::test::test_entries ... ok
test node::address::store::test::test_get_none ... ok
test node::address::store::test::test_insert_and_get ... ok
test node::address::store::test::test_insert_and_remove ... ok
test node::address::store::test::test_insert_and_update ... ok
test node::address::store::test::test_insert_duplicate ... ok
test node::address::store::test::test_node_aliases ... ok
test node::address::store::test::test_remove_nothing ... ok
test node::db::test::test_version ... ok
test node::features::test::test_operations ... ok
test node::notifications::store::test::test_branch_notifications ... ok
test node::notifications::store::test::test_clear ... ok
test node::notifications::store::test::test_cob_notifications ... ok
test node::address::store::test::test_empty ... ok
test node::notifications::store::test::test_counts_by_repo ... ok
test node::notifications::store::test::test_duplicate_notifications ... ok
test node::notifications::store::test::test_notification_status ... ok
test node::policy::store::test::test_follow_and_unfollow_node ... ok
test node::policy::store::test::test_node_aliases ... ok
test node::policy::store::test::test_node_policies ... ok
test node::policy::store::test::test_node_policy ... ok
test node::policy::store::test::test_repo_policies ... ok
test node::policy::store::test::test_repo_policy ... ok
test node::policy::store::test::test_seed_and_unseed_repo ... ok
test node::policy::store::test::test_update_alias ... ok
test node::policy::store::test::test_update_scope ... ok
test node::refs::store::test::test_count ... ok
test node::refs::store::test::test_set_and_delete ... ok
test node::refs::store::test::test_set_and_get ... ok
test node::routing::test::test_count ... ok
test node::routing::test::test_entries ... ok
test node::routing::test::test_insert_and_get ... ok
test node::routing::test::test_insert_and_get_resources ... ok
test cob::thread::tests::prop_ordering ... ok
test node::routing::test::test_insert_duplicate ... ok
test node::routing::test::test_len ... ok
test node::routing::test::test_insert_and_remove ... ok
test node::routing::test::test_insert_existing_updated_time ... ok
test node::routing::test::test_remove_many ... ok
test node::routing::test::test_update_existing_multi ... ok
test node::sync::announce::test::announcer_must_reach_preferred_seeds ... ok
test node::routing::test::test_remove_redundant ... ok
test node::sync::announce::test::announcer_reached_max_replication_target ... ok
test node::routing::test::test_prune ... ok
test node::sync::announce::test::announcer_timed_out ... ok
test node::sync::announce::test::announcer_reached_min_replication_target ... ok
test node::sync::announce::test::cannot_construct_announcer ... ok
test node::sync::announce::test::announcer_will_minimise_replication_factor ... ok
test node::sync::fetch::test::all_nodes_are_candidates ... ok
test node::sync::fetch::test::all_nodes_are_fetchable ... ok
test node::sync::fetch::test::could_not_reach_target ... ok
test node::sync::fetch::test::preferred_seeds_target_returned_over_replicas ... ok
test node::sync::fetch::test::ignores_duplicates_and_local_node ... ok
test node::sync::fetch::test::reaches_target_of_max_replicas ... ok
test node::sync::fetch::test::reaches_target_of_preferred_seeds ... ok
test node::sync::test::replicas_constrain_to ... ok
test node::test::test_alias ... ok
test node::test::test_command_result ... ok
test node::test::test_user_agent ... ok
test node::timestamp::tests::test_timestamp_max ... ok
test node::sync::fetch::test::reaches_target_of_replicas ... ok
test node::sync::test::ensure_replicas_construction ... ok
test profile::test::canonicalize_home ... ok
test profile::test::test_config ... ok
test rad::tests::test_checkout ... ok
test rad::tests::test_init ... ok
test serde_ext::test::test_localtime ... ok
test serde_ext::test::test_localtime_ext ... ok
test rad::tests::test_fork ... ok
test profile::config::test::schema ... ok
test storage::git::tests::test_references_of ... ok
test storage::git::transport::local::url::test::test_url_parse ... ok
test storage::git::transport::local::url::test::test_url_to_string ... ok
test storage::git::transport::remote::url::test::test_url_parse ... ok
test storage::refs::tests::prop_canonical_roundtrip ... ok
test storage::git::tests::test_sign_refs ... ok
test storage::tests::test_storage ... ok
test test::assert::test::assert_with_message ... ok
test test::assert::test::test_assert_no_move ... ok
test test::assert::test::test_assert_panic_0 - should panic ... ok
test test::assert::test::test_assert_panic_1 - should panic ... ok
test test::assert::test::test_assert_panic_2 - should panic ... ok
test test::assert::test::test_assert_succeed ... ok
test test::assert::test::test_panic_message ... ok
test version::test::test_version ... ok
test storage::git::tests::test_remote_refs ... ok
test storage::refs::tests::test_rid_verification ... ok
test identity::doc::test::prop_encode_decode ... ok
test result: ok. 194 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.60s
Running unittests src/lib.rs (target/debug/deps/radicle_cli-d9e40ace58972c16)
running 14 tests
test commands::rad_patch::review::builder::tests::test_review_comments_basic ... ok
test commands::rad_patch::review::builder::tests::test_review_comments_before ... ok
test commands::rad_patch::review::builder::tests::test_review_comments_split_hunk ... ok
test git::pretty_diff::test::test_pretty ... ignored
test commands::rad_inspect::test::test_tree ... ok
test commands::rad_patch::review::builder::tests::test_review_comments_multiline ... ok
test git::ddiff::tests::diff_encode_decode_ddiff_hunk ... ok
test git::unified_diff::test::test_diff_content_encode_decode_content ... ok
test terminal::format::test::test_bytes ... ok
test terminal::format::test::test_strip_comments ... ok
test terminal::patch::test::test_edit_display_message ... ok
test git::unified_diff::test::test_diff_encode_decode_diff ... ok
test terminal::patch::test::test_create_display_message ... ok
test terminal::patch::test::test_update_display_message ... ok
test result: ok. 13 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.01s
Running unittests src/main.rs (target/debug/deps/rad-b27a2fb5b52a235d)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running tests/commands.rs (target/debug/deps/commands-9645aacdb6551824)
running 97 tests
test framework_home ... ok
test git_push_amend ... ok
test git_push_and_fetch ... ok
test git_push_diverge ... ok
test rad_auth ... ok
test rad_auth_errors ... ok
test rad_block ... ok
test rad_checkout ... ok
test git_push_rollback ... ok
test git_push_converge ... ok
test git_tag ... ok
test rad_clone ... ok
test rad_clone_connect ... ok
test rad_clean ... ok
test rad_clone_unknown ... ok
test rad_clone_all ... ok
test rad_clone_directory ... ok
test rad_cob_multiset ... ok
test rad_cob_log ... ok
test rad_cob_migrate ... ok
test rad_clone_partial_fail ... ok
test rad_cob_show ... ok
test rad_config ... ok
test rad_cob_update_identity ... ok
test rad_cob_update ... ok
test rad_diff ... ok
test rad_id_collaboration ... ignored, slow
test rad_id ... ok
test rad_id_conflict ... ok
test rad_id_private ... ok
test rad_id_multi_delegate ... ok
test rad_id_threshold ... ok
test rad_id_unknown_field ... ok
test rad_id_update_delete_field ... ok
test rad_id_threshold_soft_fork ... ok
test rad_init ... ignored, part of many other tests
test rad_init_existing ... ok
test rad_init_no_git ... ok
test rad_init_no_seed ... ok
test rad_init_private ... ok
test rad_init_private_clone ... ok
test rad_inbox ... ok
test rad_init_private_no_seed ... ok
test rad_fork ... ok
test rad_fetch ... ok
test rad_init_private_clone_seed ... ok
test rad_init_sync_not_connected ... ok
test rad_init_private_seed ... ok
test rad_init_sync_preferred ... ok
test rad_init_with_existing_remote ... ok
test rad_inspect ... ok
test rad_issue ... ok
test rad_merge_after_update ... ok
test rad_merge_no_ff ... ok
test rad_merge_via_push ... ok
test rad_node_connect ... ok
test rad_node_connect_without_address ... ok
test rad_node ... ok
test rad_patch ... ok
test rad_patch_change_base ... ok
test rad_patch_ahead_behind ... ok
test rad_patch_checkout ... ok
test rad_patch_checkout_revision ... ok
test rad_patch_checkout_force ... ok
test rad_patch_detached_head ... ok
test rad_patch_diff ... ok
test rad_init_sync_and_clone ... ok
test rad_init_sync_timeout ... ok
test rad_patch_draft ... ok
test rad_patch_edit ... ok
test rad_patch_fetch_2 ... ok
test rad_patch_merge_draft ... ok
test rad_patch_fetch_1 ... ok
test rad_patch_delete ... ok
test rad_patch_revert_merge ... ok
test rad_patch_update ... ok
test rad_patch_open_explore ... ok
test rad_publish ... ok
test rad_patch_via_push ... ok
test rad_review_by_hunk ... ok
test rad_seed_and_follow ... ok
test rad_remote ... ok
test rad_self ... ok
test rad_push_and_pull_patches ... ok
test rad_seed_many ... ok
test rad_sync_without_node ... ok
test rad_unseed ... ok
test rad_warn_old_nodes ... FAILED
test rad_unseed_many ... ok
test rad_sync ... ok
test test_clone_without_seeds ... ok
test rad_watch ... ok
test test_cob_deletion ... ok
test test_cob_replication ... ok
test rad_workflow ... ok
test rad_patch_pull_update ... ok
test test_replication_via_seed ... ok
failures:
---- rad_warn_old_nodes stdout ----
1752682780 test: Using PATH ["/31de768b-be18-4ab7-9637-0c3f74b4908e/w/crates/radicle-cli/target/debug", "/usr/local/cargo/bin", "/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin", "/tmp/radicle-fOZHPb/work/alice"]
1752682780 test: rad-warn-old-nodes.md: Running `/31de768b-be18-4ab7-9637-0c3f74b4908e/w/target/debug/rad` with ["config", "push", "preferredSeeds", "z6MkrLMMsiPWUcNPHcRajuMi9mDfYckSoJyPwwnknocNYPm7@seed.radicle.garden:8776"] in `/tmp/radicle-fOZHPb/work/alice`..
1752682780 test: rad-warn-old-nodes.md: Running `/31de768b-be18-4ab7-9637-0c3f74b4908e/w/target/debug/rad` with ["config", "push", "node.connect", "z6Mkmqogy2qEM2ummccUthFEaaHvyYmYBYh3dbe9W4ebScxo@ash.radicle.garden:8776"] in `/tmp/radicle-fOZHPb/work/alice`..
1752682780 test: rad-warn-old-nodes.md: Running `/31de768b-be18-4ab7-9637-0c3f74b4908e/w/target/debug/rad` with ["debug"] in `/tmp/radicle-fOZHPb/work/alice`..
thread 'rad_warn_old_nodes' panicked at crates/radicle-cli-test/src/lib.rs:487:36:
--- Expected
++++ actual: stdout
1 1 | {
2 2 | "radExe": "[..]",
3 3 | "radVersion": "[..]",
4 - "radicleNodeVersion": "radicle-node [..]",
5 - "gitRemoteRadVersion": "git-remote-rad [..]",
6 - "gitVersion": "git version [..]",
7 - "sshVersion": "[..]",
8 - "gitHead": "[..]",
4 + "radicleNodeVersion": "<unknown>",
5 + "gitRemoteRadVersion": "git-remote-rad pre-release (b23e506f)",
6 + "gitVersion": "git version 2.39.5",
7 + "sshVersion": "OpenSSH_9.2p1 Debian-2+deb12u6, OpenSSL 3.0.16 11 Feb 2025",
8 + "gitHead": "b23e506f",
9 9 | "log": {
10 10 | "filename": "[..]",
11 11 | "exists": false,
12 12 | "len": null
13 13 | },
⋮
29 29 | "warnings": [
30 30 | "Value of configuration option `node.connect` at index 0 mentions node with address 'ash.radicle.garden:8776', which has been renamed to 'rosa.radicle.xyz:8776'. Please update your configuration.",
31 31 | "Value of configuration option `preferred_seeds` at index 0 mentions node with address 'seed.radicle.garden:8776', which has been renamed to 'iris.radicle.xyz:8776'. Please update your configuration."
32 32 | ]
33 33 | }
Exit status: 0
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
rad_warn_old_nodes
test result: FAILED. 94 passed; 1 failed; 2 ignored; 0 measured; 0 filtered out; finished in 70.45s
error: test failed, to rerun pass `-p radicle-cli --test commands`
Running unittests src/lib.rs (target/debug/deps/radicle_cli_test-b2a3ecc659957763)
running 3 tests
test tests::test_parse ... ok
test tests::test_run ... ok
test tests::test_example_spaced_brackets ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
Running unittests src/lib.rs (target/debug/deps/radicle_cob-65db1d3d21109e11)
running 8 tests
test object::tests::test_serde ... ok
test tests::invalid_parse_refstr ... ok
test tests::parse_refstr ... ok
test tests::traverse_cobs ... ok
test tests::update_cob ... ok
test type_name::test::valid_typenames ... ok
test tests::list_cobs ... ok
test tests::roundtrip ... ok
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s
Running unittests src/lib.rs (target/debug/deps/radicle_crypto-0912e5a263b454ad)
running 12 tests
test ssh::fmt::test::test_key ... ok
test ssh::keystore::tests::test_init_no_passphrase ... ok
test ssh::fmt::test::test_fingerprint ... ok
test ssh::test::test_agent_encoding_remove ... ok
test ssh::test::test_agent_encoding_sign ... ok
test ssh::test::prop_encode_decode_sk ... ok
test tests::prop_encode_decode ... ok
test tests::test_e25519_dh ... ok
test tests::test_encode_decode ... ok
test tests::prop_key_equality ... ok
test ssh::keystore::tests::test_signer ... ok
test ssh::keystore::tests::test_init_passphrase ... ok
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.87s
Running unittests src/lib.rs (target/debug/deps/radicle_dag-20ca1aca3d76c348)
running 20 tests
test tests::test_contains ... ok
test tests::test_dependencies ... ok
test tests::test_diamond ... ok
test tests::test_complex ... ok
test tests::test_cycle ... ok
test tests::test_fold_multiple_roots ... ok
test tests::test_fold_diamond ... ok
test tests::test_fold_sorting_1 ... ok
test tests::test_fold_sorting_2 ... ok
test tests::test_is_empty ... ok
test tests::test_len ... ok
test tests::test_merge_1 ... ok
test tests::test_prune_1 ... ok
test tests::test_fold_reject ... ok
test tests::test_prune_2 ... ok
test tests::test_merge_2 ... ok
test tests::test_siblings ... ok
test tests::test_prune_by_sorting ... ok
test tests::test_remove ... ok
test tests::test_get ... ok
test result: ok. 20 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_fetch-7573e472dcbfe4d4)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_node-b7f6db91647cc186)
running 69 tests
test control::tests::test_control_socket ... ok
test control::tests::test_seed_unseed ... ok
test tests::e2e::missing_default_branch ... ok
test tests::e2e::missing_delegate_default_branch ... ok
test tests::e2e::test_catchup_on_refs_announcements ... ok
test tests::e2e::test_background_foreground_fetch ... ok
test tests::e2e::test_channel_reader_limit ... ok
test tests::e2e::test_clone ... ok
test tests::e2e::test_dont_fetch_owned_refs ... ok
test tests::e2e::test_fetch_followed_remotes ... ok
test tests::e2e::test_connection_crossing ... ok
test tests::e2e::test_fetch_preserve_owned_refs ... ok
test tests::e2e::test_fetch_unseeded ... ok
test tests::e2e::test_fetch_up_to_date ... ok
test tests::e2e::test_inventory_sync_basic ... ok
test tests::e2e::test_concurrent_fetches ... ok
test tests::e2e::test_large_fetch ... ok
test tests::e2e::test_migrated_clone ... ok
test tests::e2e::test_missing_remote ... ok
test tests::e2e::test_multiple_offline_inits ... ok
test tests::e2e::test_non_fastforward_sigrefs ... ok
test tests::e2e::test_outdated_delegate_sigrefs ... ok
test tests::e2e::test_outdated_sigrefs ... ok
test tests::e2e::test_replication ... ok
test tests::e2e::test_inventory_sync_bridge ... ok
test tests::e2e::test_inventory_sync_ring ... ok
test tests::e2e::test_replication_invalid ... ok
test tests::e2e::test_replication_ref_in_sigrefs ... ok
test tests::e2e::test_inventory_sync_star ... ok
test tests::test_announcement_rebroadcast ... ok
test tests::test_announcement_rebroadcast_duplicates ... ok
test tests::test_announcement_relay ... ok
test tests::test_connection_kept_alive ... ok
test tests::test_announcement_rebroadcast_timestamp_filtered ... ok
test tests::test_disconnecting_unresponsive_peer ... ok
test tests::test_fetch_missing_inventory_on_gossip ... ok
test tests::test_fetch_missing_inventory_on_schedule ... ok
test tests::test_inbound_connection ... ok
test tests::test_inventory_decode ... ok
test tests::test_init_and_seed ... ok
test tests::test_inventory_relay ... ok
test tests::test_inventory_relay_bad_timestamp ... ok
test tests::test_inventory_sync ... ok
test tests::test_maintain_connections ... ok
test tests::test_maintain_connections_failed_attempt ... ok
test tests::test_maintain_connections_transient ... ok
test tests::test_inventory_pruning ... ok
test tests::test_outbound_connection ... ok
test tests::test_persistent_peer_connect ... ok
test tests::test_persistent_peer_reconnect_success ... ok
test tests::test_persistent_peer_reconnect_attempt ... ok
test tests::test_ping_response ... ok
test tests::test_queued_fetch_from_ann_same_rid ... ok
test tests::test_queued_fetch_from_command_same_rid ... ok
test tests::test_queued_fetch_max_capacity ... ok
test tests::test_redundant_connect ... ok
test tests::test_refs_announcement_followed ... ok
test tests::test_refs_announcement_fetch_trusted_no_inventory ... ok
test tests::test_refs_announcement_no_subscribe ... ok
test tests::test_refs_announcement_offline ... ok
test tests::test_refs_announcement_relay_private ... ok
test tests::test_refs_synced_event ... ok
test tests::test_refs_announcement_relay_public ... ok
test tests::test_seed_repo_subscribe ... ok
test wire::test::test_inventory_ann_with_extension ... ok
test wire::test::test_pong_message_with_extension ... ok
test tests::test_seeding ... ok
test tests::prop_inventory_exchange_dense ... ok
test tests::test_announcement_message_amplification ... ok
test result: ok. 69 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 19.07s
Running unittests src/main.rs (target/debug/deps/radicle_node-2d6e5b1850bfcc50)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_protocol-59d784d512b31a7c)
running 45 tests
test deserializer::test::test_decode_next ... ok
test deserializer::test::test_unparsed ... ok
test service::filter::test::test_parameters ... ok
test deserializer::test::prop_decode_next ... ok
test service::limiter::test::test_limitter_different_rates ... ok
test service::limiter::test::test_limitter_multi ... ok
test service::limiter::test::test_limitter_refill ... ok
test service::gossip::store::test::test_announced ... ok
test service::filter::test::test_sizes ... ok
test service::message::tests::test_inventory_limit ... ok
test service::message::tests::test_ref_remote_limit ... ok
test wire::frame::test::test_stream_id ... ok
test wire::message::tests::prop_addr ... ok
test service::message::tests::prop_refs_announcement_signing ... ok
test wire::message::tests::prop_zero_bytes_encode_decode ... ok
test wire::message::tests::test_inv_ann_max_size ... ok
test wire::message::tests::test_node_ann_max_size ... ok
test wire::message::tests::test_ping_encode_size_overflow - should panic ... ok
test wire::message::tests::test_pingpong_encode_max_size ... ok
test wire::message::tests::test_pong_encode_size_overflow - should panic ... ok
test wire::message::tests::test_refs_ann_max_size ... ok
test wire::tests::prop_filter ... ok
test wire::message::tests::prop_message_encode_decode ... ok
test wire::tests::prop_oid ... ok
test wire::tests::prop_id ... ok
test wire::tests::prop_refs ... ok
test wire::message::tests::prop_message_decoder ... ok
test wire::tests::prop_signature ... ok
test wire::tests::prop_string ... ok
test wire::tests::prop_tuple ... ok
test wire::tests::prop_u16 ... ok
test wire::tests::prop_u32 ... ok
test wire::tests::prop_u64 ... ok
test wire::tests::prop_u8 ... ok
test wire::tests::prop_pubkey ... ok
test wire::tests::test_alias ... ok
test wire::tests::prop_vec ... ok
test wire::tests::test_bounded_vec_limit ... ok
test wire::tests::test_string ... ok
test wire::tests::test_filter_invalid ... ok
test wire::varint::test::prop_encode_decode ... ok
test wire::varint::test::test_encode_overflow - should panic ... ok
test wire::varint::test::test_encoding ... ok
test wire::tests::prop_signed_refs ... ok
test service::message::tests::test_node_announcement_validate ... ok
test result: ok. 45 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.00s
Running unittests src/lib.rs (target/debug/deps/radicle_remote_helper-7fbc4da8b88a44e3)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/git-remote-rad.rs (target/debug/deps/git_remote_rad-c2a0c992e7e236fc)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/main.rs (target/debug/deps/radicle_schemars-6a8216b8cd8d4686)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_signals-ad41f42c3d3e47ce)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_ssh-02e22359ef9bf046)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_systemd-28e02dc067eac38d)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/lib.rs (target/debug/deps/radicle_term-6894c7dd8f5147a5)
running 20 tests
test cell::test::test_width ... ok
test ansi::tests::colors_enabled ... ok
test ansi::tests::wrapping ... ok
test ansi::tests::colors_disabled ... ok
test element::test::test_truncate ... ok
test element::test::test_width ... ok
test table::test::test_table ... ok
test table::test::test_table_border ... ok
test table::test::test_table_border_maximized ... ok
test table::test::test_table_truncate ... ok
test table::test::test_table_border_truncated ... ok
test table::test::test_table_unicode_truncate ... ok
test table::test::test_truncate ... ok
test table::test::test_table_unicode ... ok
test textarea::test::test_wrapping_code_block ... ok
test vstack::test::test_vstack ... ok
test textarea::test::test_wrapping ... ok
test textarea::test::test_wrapping_fenced_block ... ok
test textarea::test::test_wrapping_paragraphs ... ok
test vstack::test::test_vstack_maximize ... ok
test result: ok. 20 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle
running 1 test
test crates/radicle/src/cob/patch/encoding/review.rs - cob::patch::encoding::review::Review (line 23) ... ignored
test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_cli
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_cli_test
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_cob
running 1 test
test crates/radicle-cob/src/backend/git/stable.rs - backend::git::stable::with_advanced_timestamp (line 56) ... ignored
test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_crypto
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_dag
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_fetch
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_node
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_protocol
running 6 tests
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::max (line 96) ... ok
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::collect_from (line 30) ... ok
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::truncate (line 50) ... ok
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::push (line 122) ... ok
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::with_capacity (line 66) ... ok
test crates/radicle-protocol/src/bounded.rs - bounded::BoundedVec<T,N>::unbound (line 149) ... ok
test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.53s
Doc-tests radicle_remote_helper
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_signals
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_ssh
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_systemd
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests radicle_term
running 1 test
test crates/radicle-term/src/table.rs - table (line 4) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.50s
error: 1 target failed:
`-p radicle-cli --test commands`
Exit code: 101
{
"response": "finished",
"result": "failure"
}