protocol: Reimplement encoding on top of `bytes`
This commit is contained in:
parent
1c20f64a26
commit
3c5668edd2
|
|
@ -349,6 +349,12 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytesize"
|
name = "bytesize"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
|
|
@ -2643,7 +2649,7 @@ dependencies = [
|
||||||
"amplify",
|
"amplify",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bloomy",
|
"bloomy",
|
||||||
"byteorder",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"colored",
|
"colored",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
|
|
@ -2680,7 +2686,7 @@ name = "radicle-protocol"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bloomy",
|
"bloomy",
|
||||||
"byteorder",
|
"bytes",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"cyphernet",
|
"cyphernet",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ rust-version = "1.81.0"
|
||||||
amplify = { version = "4.0.0", default-features = false }
|
amplify = { version = "4.0.0", default-features = false }
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
bstr = "1.3"
|
bstr = "1.3"
|
||||||
byteorder = "1.4"
|
bytes = "1"
|
||||||
chrono = { version = "0.4.26", default-features = false }
|
chrono = { version = "0.4.26", default-features = false }
|
||||||
colored = "2.1.0"
|
colored = "2.1.0"
|
||||||
crossbeam-channel = "0.5.6"
|
crossbeam-channel = "0.5.6"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ test = ["radicle/test", "radicle-crypto/test", "radicle-crypto/cyphernet", "radi
|
||||||
amplify = { workspace = true }
|
amplify = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
bloomy = "1.2"
|
bloomy = "1.2"
|
||||||
byteorder = { workspace = true }
|
bytes = { workspace = true }
|
||||||
chrono = { workspace = true, features = ["clock"] }
|
chrono = { workspace = true, features = ["clock"] }
|
||||||
colored = { workspace = true }
|
colored = { workspace = true }
|
||||||
crossbeam-channel = { workspace = true }
|
crossbeam-channel = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,8 @@ fn test_inventory_decode() {
|
||||||
let timestamp: Timestamp = LocalTime::now().into();
|
let timestamp: Timestamp = LocalTime::now().into();
|
||||||
|
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
inventory.as_slice().encode(&mut buf).unwrap();
|
inventory.as_slice().encode(&mut buf);
|
||||||
timestamp.encode(&mut buf).unwrap();
|
timestamp.encode(&mut buf);
|
||||||
|
|
||||||
let m = InventoryAnnouncement::decode(&mut buf.as_slice()).expect("message decodes");
|
let m = InventoryAnnouncement::decode(&mut buf.as_slice()).expect("message decodes");
|
||||||
assert_eq!(inventory.as_slice(), m.inventory.as_slice());
|
assert_eq!(inventory.as_slice(), m.inventory.as_slice());
|
||||||
|
|
|
||||||
|
|
@ -1001,9 +1001,7 @@ where
|
||||||
metrics.sent_gossip_messages += msgs.len();
|
metrics.sent_gossip_messages += msgs.len();
|
||||||
|
|
||||||
for msg in msgs {
|
for msg in msgs {
|
||||||
Frame::gossip(link, msg)
|
Frame::gossip(link, msg).encode(&mut data);
|
||||||
.encode(&mut data)
|
|
||||||
.expect("in-memory writes never fail");
|
|
||||||
}
|
}
|
||||||
metrics.sent_bytes += data.len();
|
metrics.sent_bytes += data.len();
|
||||||
|
|
||||||
|
|
@ -1262,18 +1260,16 @@ mod test {
|
||||||
let pong = Message::Pong {
|
let pong = Message::Pong {
|
||||||
zeroes: ZeroBytes::new(42),
|
zeroes: ZeroBytes::new(42),
|
||||||
};
|
};
|
||||||
frame::PROTOCOL_VERSION_STRING.encode(&mut stream).unwrap();
|
frame::PROTOCOL_VERSION_STRING.encode(&mut stream);
|
||||||
frame::StreamId::gossip(Link::Outbound)
|
frame::StreamId::gossip(Link::Outbound).encode(&mut stream);
|
||||||
.encode(&mut stream)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Serialize gossip message with some extension fields.
|
// Serialize gossip message with some extension fields.
|
||||||
let mut gossip = wire::serialize(&pong);
|
let mut gossip = wire::serialize(&pong);
|
||||||
String::from("extra").encode(&mut gossip).unwrap();
|
String::from("extra").encode(&mut gossip);
|
||||||
48u8.encode(&mut gossip).unwrap();
|
48u8.encode(&mut gossip);
|
||||||
|
|
||||||
// Encode gossip message using the varint-prefix format into the stream.
|
// 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);
|
let mut de = deserializer::Deserializer::<1024, Frame>::new(1024);
|
||||||
de.input(&stream).unwrap();
|
de.input(&stream).unwrap();
|
||||||
|
|
@ -1298,16 +1294,14 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for MessageWithExt {
|
impl wire::Encode for MessageWithExt {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, writer: &mut impl bytes::BufMut) {
|
||||||
let mut n = self.msg.encode(writer)?;
|
self.msg.encode(writer);
|
||||||
n += self.ext.encode(writer)?;
|
self.ext.encode(writer);
|
||||||
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Decode for MessageWithExt {
|
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 msg = Message::decode(reader)?;
|
||||||
let ext = String::decode(reader).unwrap_or_default();
|
let ext = String::decode(reader).unwrap_or_default();
|
||||||
|
|
||||||
|
|
@ -1337,12 +1331,9 @@ mod test {
|
||||||
ext: String::from("extra"),
|
ext: String::from("extra"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.encode(&mut stream)
|
.encode(&mut stream);
|
||||||
.unwrap();
|
|
||||||
// Pong message that comes after, without extension.
|
// Pong message that comes after, without extension.
|
||||||
frame::Frame::gossip(Link::Outbound, pong.clone())
|
frame::Frame::gossip(Link::Outbound, pong.clone()).encode(&mut stream);
|
||||||
.encode(&mut stream)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// First test deserializing using the message with extension type.
|
// First test deserializing using the message with extension type.
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ test = ["radicle/test", "radicle-crypto/test", "radicle-crypto/cyphernet", "qche
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bloomy = "1.2"
|
bloomy = "1.2"
|
||||||
byteorder = { workspace = true }
|
bytes = { workspace = true }
|
||||||
crossbeam-channel = { workspace = true }
|
crossbeam-channel = { workspace = true }
|
||||||
cyphernet = { workspace = true, features = ["tor"] }
|
cyphernet = { workspace = true, features = ["tor"] }
|
||||||
fastrand = { workspace = true }
|
fastrand = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use radicle_node::bounded;
|
/// use radicle_protocol::bounded;
|
||||||
///
|
///
|
||||||
/// let mut iter = (0..4).into_iter();
|
/// let mut iter = (0..4).into_iter();
|
||||||
/// let bounded: bounded::BoundedVec<i32,3> = bounded::BoundedVec::collect_from(&mut 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
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use radicle_node::bounded;
|
/// use radicle_protocol::bounded;
|
||||||
///
|
///
|
||||||
/// let mut vec = vec![1, 2, 3];
|
/// let mut vec = vec![1, 2, 3];
|
||||||
/// let bounded = bounded::BoundedVec::<_, 2>::truncate(vec);
|
/// let bounded = bounded::BoundedVec::<_, 2>::truncate(vec);
|
||||||
|
|
@ -64,7 +64,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use radicle_node::bounded;
|
/// use radicle_protocol::bounded;
|
||||||
///
|
///
|
||||||
/// let vec = bounded::BoundedVec::<i32, 11>::with_capacity(10).unwrap();
|
/// let vec = bounded::BoundedVec::<i32, 11>::with_capacity(10).unwrap();
|
||||||
///
|
///
|
||||||
|
|
@ -94,7 +94,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use radicle_node::bounded;
|
/// use radicle_protocol::bounded;
|
||||||
///
|
///
|
||||||
/// type Inventory = bounded::BoundedVec<(), 10>;
|
/// type Inventory = bounded::BoundedVec<(), 10>;
|
||||||
/// assert_eq!(Inventory::max(), 10);
|
/// assert_eq!(Inventory::max(), 10);
|
||||||
|
|
@ -120,7 +120,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use radicle_node::bounded;
|
/// use radicle_protocol::bounded;
|
||||||
///
|
///
|
||||||
/// let mut vec: bounded::BoundedVec<_,3> = vec![1, 2].try_into().unwrap();
|
/// let mut vec: bounded::BoundedVec<_,3> = vec![1, 2].try_into().unwrap();
|
||||||
/// vec.push(3).expect("within limit");
|
/// vec.push(3).expect("within limit");
|
||||||
|
|
@ -147,7 +147,7 @@ impl<T, const N: usize> BoundedVec<T, N> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use radicle_node::bounded;
|
/// use radicle_protocol::bounded;
|
||||||
///
|
///
|
||||||
/// let mut bounded: bounded::BoundedVec<_,3> = vec![1, 2, 3].try_into().unwrap();
|
/// let mut bounded: bounded::BoundedVec<_,3> = vec![1, 2, 3].try_into().unwrap();
|
||||||
/// let mut vec = bounded.unbound();
|
/// 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"))]
|
#[cfg(any(test, feature = "test"))]
|
||||||
impl<T, const N: usize> qcheck::Arbitrary for BoundedVec<T, N>
|
impl<T, const N: usize> qcheck::Arbitrary for BoundedVec<T, N>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ impl<const B: usize, D: wire::Decode> Deserializer<B, D> {
|
||||||
|
|
||||||
Ok(Some(msg))
|
Ok(Some(msg))
|
||||||
}
|
}
|
||||||
Err(err) if err.is_eof() => Ok(None),
|
Err(wire::Error::UnexpectedEnd { .. }) => Ok(None),
|
||||||
Err(err) => Err(err),
|
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> {
|
impl<const B: usize, D: wire::Decode> io::Write for Deserializer<B, D> {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
self.input(buf).map_err(|_| io::ErrorKind::OutOfMemory)?;
|
self.input(buf).map_err(|_| io::ErrorKind::OutOfMemory)?;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use std::{fmt, io, mem};
|
use std::{fmt, mem};
|
||||||
|
|
||||||
|
use bytes::{Buf, BufMut};
|
||||||
use nonempty::NonEmpty;
|
use nonempty::NonEmpty;
|
||||||
|
|
||||||
use radicle::crypto;
|
use radicle::crypto;
|
||||||
use radicle::git;
|
use radicle::git;
|
||||||
use radicle::identity::RepoId;
|
use radicle::identity::RepoId;
|
||||||
|
|
@ -117,32 +119,28 @@ impl NodeAnnouncement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for NodeAnnouncement {
|
impl wire::Encode for NodeAnnouncement {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = 0;
|
self.version.encode(buf);
|
||||||
|
self.features.encode(buf);
|
||||||
n += self.version.encode(writer)?;
|
self.timestamp.encode(buf);
|
||||||
n += self.features.encode(writer)?;
|
self.alias.encode(buf);
|
||||||
n += self.timestamp.encode(writer)?;
|
self.addresses.encode(buf);
|
||||||
n += self.alias.encode(writer)?;
|
self.nonce.encode(buf);
|
||||||
n += self.addresses.encode(writer)?;
|
self.agent.encode(buf);
|
||||||
n += self.nonce.encode(writer)?;
|
|
||||||
n += self.agent.encode(writer)?;
|
|
||||||
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Decode for NodeAnnouncement {
|
impl wire::Decode for NodeAnnouncement {
|
||||||
fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
|
||||||
let version = u8::decode(reader)?;
|
let version = u8::decode(buf)?;
|
||||||
let features = node::Features::decode(reader)?;
|
let features = node::Features::decode(buf)?;
|
||||||
let timestamp = Timestamp::decode(reader)?;
|
let timestamp = Timestamp::decode(buf)?;
|
||||||
let alias = wire::Decode::decode(reader)?;
|
let alias = wire::Decode::decode(buf)?;
|
||||||
let addresses = BoundedVec::<Address, ADDRESS_LIMIT>::decode(reader)?;
|
let addresses = BoundedVec::<Address, ADDRESS_LIMIT>::decode(buf)?;
|
||||||
let nonce = u64::decode(reader)?;
|
let nonce = u64::decode(buf)?;
|
||||||
let agent = match UserAgent::decode(reader) {
|
let agent = match UserAgent::decode(buf) {
|
||||||
Ok(ua) => ua,
|
Ok(ua) => ua,
|
||||||
Err(e) if e.is_eof() => UserAgent::default(),
|
Err(wire::Error::UnexpectedEnd { .. }) => UserAgent::default(),
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -708,8 +706,8 @@ mod tests {
|
||||||
.signed(&Device::mock())
|
.signed(&Device::mock())
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let mut buf: Vec<u8> = Vec::new();
|
let mut buf = Vec::new();
|
||||||
assert!(msg.encode(&mut buf).is_ok());
|
msg.encode(&mut buf);
|
||||||
|
|
||||||
let decoded = wire::deserialize(buf.as_slice());
|
let decoded = wire::deserialize(buf.as_slice());
|
||||||
assert!(decoded.is_ok());
|
assert!(decoded.is_ok());
|
||||||
|
|
@ -728,10 +726,7 @@ mod tests {
|
||||||
&Device::mock(),
|
&Device::mock(),
|
||||||
);
|
);
|
||||||
let mut buf: Vec<u8> = Vec::new();
|
let mut buf: Vec<u8> = Vec::new();
|
||||||
assert!(
|
msg.encode(&mut buf);
|
||||||
msg.encode(&mut buf).is_ok(),
|
|
||||||
"INVENTORY_LIMIT is a valid limit for encoding",
|
|
||||||
);
|
|
||||||
|
|
||||||
let decoded = wire::deserialize(buf.as_slice());
|
let decoded = wire::deserialize(buf.as_slice());
|
||||||
assert!(
|
assert!(
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,13 @@ pub use message::{AddressType, MessageType};
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use std::mem;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
use std::{io, mem};
|
|
||||||
|
|
||||||
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
|
use bytes::{Buf, BufMut};
|
||||||
|
|
||||||
use cyphernet::addr::tor;
|
use cyphernet::addr::tor;
|
||||||
|
|
||||||
use radicle::crypto::{PublicKey, Signature, Unverified};
|
use radicle::crypto::{PublicKey, Signature, Unverified};
|
||||||
|
|
@ -41,8 +42,6 @@ pub type Size = u16;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("i/o: {0}")]
|
|
||||||
Io(#[from] io::Error),
|
|
||||||
#[error("UTF-8 error: {0}")]
|
#[error("UTF-8 error: {0}")]
|
||||||
FromUtf8(#[from] FromUtf8Error),
|
FromUtf8(#[from] FromUtf8Error),
|
||||||
#[error("invalid size: expected {expected}, got {actual}")]
|
#[error("invalid size: expected {expected}, got {actual}")]
|
||||||
|
|
@ -75,24 +74,32 @@ pub enum Error {
|
||||||
UnknownInfoType(u16),
|
UnknownInfoType(u16),
|
||||||
#[error("unexpected bytes")]
|
#[error("unexpected bytes")]
|
||||||
UnexpectedBytes,
|
UnexpectedBytes,
|
||||||
|
#[error("unexpected end of buffer, requested {requested} more bytes but only {available} are available")]
|
||||||
|
UnexpectedEnd { available: usize, requested: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl From<bytes::TryGetError> for Error {
|
||||||
/// Whether we've reached the end of file. This will be true when we fail to decode
|
fn from(
|
||||||
/// a message because there's not enough data in the stream.
|
bytes::TryGetError {
|
||||||
pub fn is_eof(&self) -> bool {
|
available,
|
||||||
matches!(self, Self::Io(err) if err.kind() == io::ErrorKind::UnexpectedEof)
|
requested,
|
||||||
|
}: bytes::TryGetError,
|
||||||
|
) -> Self {
|
||||||
|
Self::UnexpectedEnd {
|
||||||
|
available,
|
||||||
|
requested,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Things that can be encoded as binary.
|
/// Things that can be encoded as binary.
|
||||||
pub trait Encode {
|
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.
|
/// Things that can be decoded from binary.
|
||||||
pub trait Decode: Sized {
|
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.
|
/// Encode an object into a byte vector.
|
||||||
|
|
@ -100,79 +107,62 @@ pub trait Decode: Sized {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If the encoded object exceeds [`Size::MAX`].
|
/// If the encoded object exceeds [`Size::MAX`].
|
||||||
pub fn serialize<T: Encode + ?Sized>(data: &T) -> Vec<u8> {
|
pub fn serialize<E: Encode + ?Sized>(data: &E) -> Vec<u8> {
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new().limit(Size::MAX as usize);
|
||||||
// SAFETY: We expect this to panic if the user passes
|
data.encode(&mut buffer);
|
||||||
// in data that exceeds the maximum allowed size.
|
buffer.into_inner()
|
||||||
#[allow(clippy::unwrap_used)]
|
|
||||||
let len = data.encode(&mut buffer).unwrap();
|
|
||||||
|
|
||||||
debug_assert_eq!(len, buffer.len());
|
|
||||||
|
|
||||||
buffer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decode an object from a vector.
|
/// Decode an object from a slice.
|
||||||
pub fn deserialize<T: Decode>(data: &[u8]) -> Result<T, Error> {
|
pub fn deserialize<T: Decode>(mut data: &[u8]) -> Result<T, Error> {
|
||||||
let mut cursor = io::Cursor::new(data);
|
let result = T::decode(&mut data)?;
|
||||||
let obj = T::decode(&mut cursor)?;
|
|
||||||
|
|
||||||
if cursor.position() as usize != cursor.get_ref().len() {
|
if data.is_empty() {
|
||||||
return Err(Error::UnexpectedBytes);
|
Ok(result)
|
||||||
|
} else {
|
||||||
|
Err(Error::UnexpectedBytes)
|
||||||
}
|
}
|
||||||
Ok(obj)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for u8 {
|
impl Encode for u8 {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
writer.write_u8(*self)?;
|
buf.put_u8(*self);
|
||||||
|
|
||||||
Ok(mem::size_of::<Self>())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for u16 {
|
impl Encode for u16 {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
writer.write_u16::<NetworkEndian>(*self)?;
|
buf.put_u16(*self);
|
||||||
|
|
||||||
Ok(mem::size_of::<Self>())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for u32 {
|
impl Encode for u32 {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
writer.write_u32::<NetworkEndian>(*self)?;
|
buf.put_u32(*self);
|
||||||
|
|
||||||
Ok(mem::size_of::<Self>())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for u64 {
|
impl Encode for u64 {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
writer.write_u64::<NetworkEndian>(*self)?;
|
buf.put_u64(*self);
|
||||||
|
|
||||||
Ok(mem::size_of::<Self>())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for PublicKey {
|
impl Encode for PublicKey {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.deref().encode(writer)
|
self.deref().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const T: usize> Encode for &[u8; T] {
|
impl<const T: usize> Encode for &[u8; T] {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
writer.write_all(&**self)?;
|
buf.put_slice(&**self);
|
||||||
Ok(mem::size_of::<Self>())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const T: usize> Encode for [u8; T] {
|
impl<const T: usize> Encode for [u8; T] {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
writer.write_all(self)?;
|
buf.put_slice(self);
|
||||||
|
|
||||||
Ok(mem::size_of::<Self>())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,13 +170,12 @@ impl<T> Encode for &[T]
|
||||||
where
|
where
|
||||||
T: Encode,
|
T: Encode,
|
||||||
{
|
{
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = (self.len() as Size).encode(writer)?;
|
(self.len() as Size).encode(buf);
|
||||||
|
|
||||||
for item in self.iter() {
|
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
|
where
|
||||||
T: Encode,
|
T: Encode,
|
||||||
{
|
{
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.as_slice().encode(writer)
|
self.as_slice().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for &str {
|
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);
|
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();
|
let bytes = self.as_bytes();
|
||||||
|
|
||||||
// Nb. Don't use the [`Encode`] instance here for &[u8], because we are prefixing the
|
// Nb. Don't use the [`Encode`] instance here for &[u8], because we are prefixing the
|
||||||
// length ourselves.
|
// length ourselves.
|
||||||
writer.write_all(bytes)?;
|
buf.put_slice(bytes);
|
||||||
|
|
||||||
Ok(n + bytes.len())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for String {
|
impl Encode for String {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.as_str().encode(writer)
|
self.as_str().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for git::Url {
|
impl Encode for git::Url {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.to_string().encode(writer)
|
self.to_string().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for RepoId {
|
impl Encode for RepoId {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.deref().encode(writer)
|
self.deref().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for Refs {
|
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
|
let len: Size = self
|
||||||
.len()
|
.len()
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
|
.expect("`Refs::len()` must be less than or equal to `Size::MAX`");
|
||||||
let mut n = len.encode(writer)?;
|
len.encode(buf);
|
||||||
|
|
||||||
for (name, oid) in self.iter() {
|
for (name, oid) in self.iter() {
|
||||||
n += name.as_str().encode(writer)?;
|
name.as_str().encode(buf);
|
||||||
n += oid.encode(writer)?;
|
oid.encode(buf);
|
||||||
}
|
}
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for cyphernet::addr::tor::OnionAddrV3 {
|
impl Encode for cyphernet::addr::tor::OnionAddrV3 {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.into_raw_bytes().encode(writer)
|
self.into_raw_bytes().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for UserAgent {
|
impl Encode for UserAgent {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.as_ref().encode(writer)
|
self.as_ref().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for Alias {
|
impl Encode for Alias {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.as_ref().encode(writer)
|
self.as_ref().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,51 +257,50 @@ where
|
||||||
A: Encode,
|
A: Encode,
|
||||||
B: Encode,
|
B: Encode,
|
||||||
{
|
{
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = self.0.encode(writer)?;
|
self.0.encode(buf);
|
||||||
n += self.1.encode(writer)?;
|
self.1.encode(buf);
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for git::RefString {
|
impl Encode for git::RefString {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.as_str().encode(writer)
|
self.as_str().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for Signature {
|
impl Encode for Signature {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.deref().encode(writer)
|
self.deref().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for git::Oid {
|
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.
|
// 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 {
|
impl Decode for PublicKey {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let buf: [u8; 32] = Decode::decode(reader)?;
|
let buf: [u8; 32] = Decode::decode(buf)?;
|
||||||
|
|
||||||
Ok(PublicKey::from(buf))
|
Ok(PublicKey::from(buf))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for Refs {
|
impl Decode for Refs {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let len = Size::decode(reader)?;
|
let len = Size::decode(buf)?;
|
||||||
let mut refs = BTreeMap::new();
|
let mut refs = BTreeMap::new();
|
||||||
|
|
||||||
for _ in 0..len {
|
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 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);
|
refs.insert(name, oid);
|
||||||
}
|
}
|
||||||
|
|
@ -324,22 +309,21 @@ impl Decode for Refs {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for git::RefString {
|
impl Decode for git::RefString {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let ref_str = String::decode(reader)?;
|
let ref_str = String::decode(buf)?;
|
||||||
git::RefString::try_from(ref_str).map_err(Error::from)
|
git::RefString::try_from(ref_str).map_err(Error::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for UserAgent {
|
impl Decode for UserAgent {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
String::decode(reader)
|
String::decode(buf).and_then(|s| UserAgent::from_str(&s).map_err(Error::InvalidUserAgent))
|
||||||
.and_then(|s| UserAgent::from_str(&s).map_err(Error::InvalidUserAgent))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for Alias {
|
impl Decode for Alias {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
String::decode(reader).and_then(|s| Alias::from_str(&s).map_err(Error::from))
|
String::decode(buf).and_then(|s| Alias::from_str(&s).map_err(Error::from))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -348,16 +332,16 @@ where
|
||||||
A: Decode,
|
A: Decode,
|
||||||
B: Decode,
|
B: Decode,
|
||||||
{
|
{
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let a = A::decode(reader)?;
|
let a = A::decode(buf)?;
|
||||||
let b = B::decode(reader)?;
|
let b = B::decode(buf)?;
|
||||||
Ok((a, b))
|
Ok((a, b))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for git::Oid {
|
impl Decode for git::Oid {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let len = Size::decode(reader)? as usize;
|
let len = Size::decode(buf)? as usize;
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
const expected: usize = mem::size_of::<git::raw::Oid>();
|
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::raw::Oid::from_bytes(&buf).expect("the buffer is exactly the right size");
|
||||||
let oid = git::Oid::from(oid);
|
let oid = git::Oid::from(oid);
|
||||||
|
|
||||||
|
|
@ -377,41 +361,41 @@ impl Decode for git::Oid {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for Signature {
|
impl Decode for Signature {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let bytes: [u8; 64] = Decode::decode(reader)?;
|
let bytes: [u8; 64] = Decode::decode(buf)?;
|
||||||
|
|
||||||
Ok(Signature::from(bytes))
|
Ok(Signature::from(bytes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for u8 {
|
impl Decode for u8 {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
reader.read_u8().map_err(Error::from)
|
Ok(buf.try_get_u8()?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for u16 {
|
impl Decode for u16 {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
reader.read_u16::<NetworkEndian>().map_err(Error::from)
|
Ok(buf.try_get_u16()?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for u32 {
|
impl Decode for u32 {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
reader.read_u32::<NetworkEndian>().map_err(Error::from)
|
Ok(buf.try_get_u32()?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for u64 {
|
impl Decode for u64 {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
reader.read_u64::<NetworkEndian>().map_err(Error::from)
|
Ok(buf.try_get_u64()?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> Decode for [u8; N] {
|
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];
|
let mut ary = [0; N];
|
||||||
reader.read_exact(&mut ary)?;
|
buf.try_copy_to_slice(&mut ary).map_err(Error::from)?;
|
||||||
|
|
||||||
Ok(ary)
|
Ok(ary)
|
||||||
}
|
}
|
||||||
|
|
@ -421,15 +405,15 @@ impl<T, const N: usize> Decode for BoundedVec<T, N>
|
||||||
where
|
where
|
||||||
T: Decode,
|
T: Decode,
|
||||||
{
|
{
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let len: usize = Size::decode(reader)? as usize;
|
let len: usize = Size::decode(buf)? as usize;
|
||||||
let mut items = Self::with_capacity(len).map_err(|_| Error::InvalidSize {
|
let mut items = Self::with_capacity(len).map_err(|_| Error::InvalidSize {
|
||||||
expected: Self::max(),
|
expected: Self::max(),
|
||||||
actual: len,
|
actual: len,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
for _ in 0..items.capacity() {
|
for _ in 0..items.capacity() {
|
||||||
let item = T::decode(reader)?;
|
let item = T::decode(buf)?;
|
||||||
items.push(item).ok();
|
items.push(item).ok();
|
||||||
}
|
}
|
||||||
Ok(items)
|
Ok(items)
|
||||||
|
|
@ -437,11 +421,11 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for String {
|
impl Decode for String {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let len = u8::decode(reader)?;
|
let len = u8::decode(buf)?;
|
||||||
let mut bytes = vec![0; len as usize];
|
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)?;
|
let string = String::from_utf8(bytes)?;
|
||||||
|
|
||||||
|
|
@ -450,32 +434,29 @@ impl Decode for String {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for RepoId {
|
impl Decode for RepoId {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let oid: git::Oid = Decode::decode(reader)?;
|
let oid: git::Oid = Decode::decode(buf)?;
|
||||||
|
|
||||||
Ok(Self::from(oid))
|
Ok(Self::from(oid))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for filter::Filter {
|
impl Encode for filter::Filter {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = 0;
|
self.deref().as_bytes().encode(buf);
|
||||||
|
|
||||||
n += self.deref().as_bytes().encode(writer)?;
|
|
||||||
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for filter::Filter {
|
impl Decode for filter::Filter {
|
||||||
fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let size: usize = Size::decode(reader)? as usize;
|
let size: usize = Size::decode(buf)? as usize;
|
||||||
if !filter::FILTER_SIZES.contains(&size) {
|
if !filter::FILTER_SIZES.contains(&size) {
|
||||||
return Err(Error::InvalidFilterSize(size));
|
return Err(Error::InvalidFilterSize(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bytes = vec![0; 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);
|
let f = filter::BloomFilter::from(bytes);
|
||||||
debug_assert_eq!(f.hashes(), filter::FILTER_HASHES);
|
debug_assert_eq!(f.hashes(), filter::FILTER_HASHES);
|
||||||
|
|
@ -485,63 +466,55 @@ impl Decode for filter::Filter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Encode for SignedRefs<V> {
|
impl<V> Encode for SignedRefs<V> {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = 0;
|
self.id.encode(buf);
|
||||||
|
self.refs.encode(buf);
|
||||||
n += self.id.encode(writer)?;
|
self.signature.encode(buf);
|
||||||
n += self.refs.encode(writer)?;
|
|
||||||
n += self.signature.encode(writer)?;
|
|
||||||
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for SignedRefs<Unverified> {
|
impl Decode for SignedRefs<Unverified> {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let id = NodeId::decode(reader)?;
|
let id = NodeId::decode(buf)?;
|
||||||
let refs = Refs::decode(reader)?;
|
let refs = Refs::decode(buf)?;
|
||||||
let signature = Signature::decode(reader)?;
|
let signature = Signature::decode(buf)?;
|
||||||
|
|
||||||
Ok(Self::new(refs, id, signature))
|
Ok(Self::new(refs, id, signature))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for RefsAt {
|
impl Encode for RefsAt {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = 0;
|
self.remote.encode(buf);
|
||||||
|
self.at.encode(buf);
|
||||||
n += self.remote.encode(writer)?;
|
|
||||||
n += self.at.encode(writer)?;
|
|
||||||
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for RefsAt {
|
impl Decode for RefsAt {
|
||||||
fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let remote = NodeId::decode(reader)?;
|
let remote = NodeId::decode(buf)?;
|
||||||
let at = git::Oid::decode(reader)?;
|
let at = git::Oid::decode(buf)?;
|
||||||
Ok(Self { remote, at })
|
Ok(Self { remote, at })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for node::Features {
|
impl Encode for node::Features {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.deref().encode(writer)
|
self.deref().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for node::Features {
|
impl Decode for node::Features {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let features = u64::decode(reader)?;
|
let features = u64::decode(buf)?;
|
||||||
|
|
||||||
Ok(Self::from(features))
|
Ok(Self::from(features))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for tor::OnionAddrV3 {
|
impl Decode for tor::OnionAddrV3 {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let bytes: [u8; tor::ONION_V3_RAW_LEN] = Decode::decode(reader)?;
|
let bytes: [u8; tor::ONION_V3_RAW_LEN] = Decode::decode(buf)?;
|
||||||
let addr = tor::OnionAddrV3::from_raw_bytes(bytes)?;
|
let addr = tor::OnionAddrV3::from_raw_bytes(bytes)?;
|
||||||
|
|
||||||
Ok(addr)
|
Ok(addr)
|
||||||
|
|
@ -549,14 +522,14 @@ impl Decode for tor::OnionAddrV3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode for Timestamp {
|
impl Encode for Timestamp {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.deref().encode(writer)
|
self.deref().encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode for Timestamp {
|
impl Decode for Timestamp {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
|
||||||
let millis = u64::decode(reader)?;
|
let millis = u64::decode(buf)?;
|
||||||
let ts = Timestamp::try_from(millis).map_err(Error::InvalidTimestamp)?;
|
let ts = Timestamp::try_from(millis).map_err(Error::InvalidTimestamp)?;
|
||||||
|
|
||||||
Ok(ts)
|
Ok(ts)
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@
|
||||||
#![warn(clippy::missing_docs_in_private_items)]
|
#![warn(clippy::missing_docs_in_private_items)]
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
|
|
||||||
|
use bytes::{Buf, BufMut};
|
||||||
|
use radicle::node::Link;
|
||||||
|
|
||||||
use crate::service::Message;
|
use crate::service::Message;
|
||||||
use crate::{wire, wire::varint, wire::varint::VarInt, PROTOCOL_VERSION};
|
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
|
/// Protocol version strings all start with the magic sequence `rad`, followed
|
||||||
/// by a version number.
|
/// by a version number.
|
||||||
|
|
@ -29,17 +31,16 @@ impl Version {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for Version {
|
impl wire::Encode for Version {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
writer.write_all(&PROTOCOL_VERSION_STRING.0)?;
|
buf.put_slice(&PROTOCOL_VERSION_STRING.0);
|
||||||
|
|
||||||
Ok(PROTOCOL_VERSION_STRING.0.len())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Decode for Version {
|
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];
|
let mut version = [0u8; 4];
|
||||||
reader.read_exact(&mut version[..])?;
|
|
||||||
|
buf.try_copy_to_slice(&mut version[..])?;
|
||||||
|
|
||||||
if version != PROTOCOL_VERSION_STRING.0 {
|
if version != PROTOCOL_VERSION_STRING.0 {
|
||||||
return Err(wire::Error::InvalidProtocolVersion(version));
|
return Err(wire::Error::InvalidProtocolVersion(version));
|
||||||
|
|
@ -144,15 +145,15 @@ impl fmt::Display for StreamId {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Decode for StreamId {
|
impl wire::Decode for StreamId {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
|
||||||
let id = VarInt::decode(reader)?;
|
let id = VarInt::decode(buf)?;
|
||||||
Ok(Self(id))
|
Ok(Self(id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for StreamId {
|
impl wire::Encode for StreamId {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
self.0.encode(writer)
|
self.0.encode(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -272,19 +273,19 @@ pub enum Control {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Decode for Control {
|
impl wire::Decode for Control {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
|
||||||
let command = u8::decode(reader)?;
|
let command = u8::decode(buf)?;
|
||||||
match command {
|
match command {
|
||||||
CONTROL_OPEN => {
|
CONTROL_OPEN => {
|
||||||
let stream = StreamId::decode(reader)?;
|
let stream = StreamId::decode(buf)?;
|
||||||
Ok(Control::Open { stream })
|
Ok(Control::Open { stream })
|
||||||
}
|
}
|
||||||
CONTROL_CLOSE => {
|
CONTROL_CLOSE => {
|
||||||
let stream = StreamId::decode(reader)?;
|
let stream = StreamId::decode(buf)?;
|
||||||
Ok(Control::Close { stream })
|
Ok(Control::Close { stream })
|
||||||
}
|
}
|
||||||
CONTROL_EOF => {
|
CONTROL_EOF => {
|
||||||
let stream = StreamId::decode(reader)?;
|
let stream = StreamId::decode(buf)?;
|
||||||
Ok(Control::Eof { stream })
|
Ok(Control::Eof { stream })
|
||||||
}
|
}
|
||||||
other => Err(wire::Error::InvalidControlMessage(other)),
|
other => Err(wire::Error::InvalidControlMessage(other)),
|
||||||
|
|
@ -293,38 +294,35 @@ impl wire::Decode for Control {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for Control {
|
impl wire::Encode for Control {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = 0;
|
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::Open { stream: id } => {
|
Self::Open { stream: id } => {
|
||||||
n += CONTROL_OPEN.encode(writer)?;
|
CONTROL_OPEN.encode(buf);
|
||||||
n += id.encode(writer)?;
|
id.encode(buf);
|
||||||
}
|
}
|
||||||
Self::Eof { stream: id } => {
|
Self::Eof { stream: id } => {
|
||||||
n += CONTROL_EOF.encode(writer)?;
|
CONTROL_EOF.encode(buf);
|
||||||
n += id.encode(writer)?;
|
id.encode(buf);
|
||||||
}
|
}
|
||||||
Self::Close { stream: id } => {
|
Self::Close { stream: id } => {
|
||||||
n += CONTROL_CLOSE.encode(writer)?;
|
CONTROL_CLOSE.encode(buf);
|
||||||
n += id.encode(writer)?;
|
id.encode(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: wire::Decode> wire::Decode for Frame<M> {
|
impl<M: wire::Decode> wire::Decode for Frame<M> {
|
||||||
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
|
||||||
let version = Version::decode(reader)?;
|
let version = Version::decode(buf)?;
|
||||||
if version.number() != PROTOCOL_VERSION {
|
if version.number() != PROTOCOL_VERSION {
|
||||||
return Err(wire::Error::WrongProtocolVersion(version.number()));
|
return Err(wire::Error::WrongProtocolVersion(version.number()));
|
||||||
}
|
}
|
||||||
let stream = StreamId::decode(reader)?;
|
let stream = StreamId::decode(buf)?;
|
||||||
|
|
||||||
match stream.kind() {
|
match stream.kind() {
|
||||||
Ok(StreamKind::Control) => {
|
Ok(StreamKind::Control) => {
|
||||||
let ctrl = Control::decode(reader)?;
|
let ctrl = Control::decode(buf)?;
|
||||||
let frame = Frame {
|
let frame = Frame {
|
||||||
version,
|
version,
|
||||||
stream,
|
stream,
|
||||||
|
|
@ -333,7 +331,7 @@ impl<M: wire::Decode> wire::Decode for Frame<M> {
|
||||||
Ok(frame)
|
Ok(frame)
|
||||||
}
|
}
|
||||||
Ok(StreamKind::Gossip) => {
|
Ok(StreamKind::Gossip) => {
|
||||||
let data = varint::payload::decode(reader)?;
|
let data = varint::payload::decode(buf)?;
|
||||||
let mut cursor = io::Cursor::new(data);
|
let mut cursor = io::Cursor::new(data);
|
||||||
let msg = M::decode(&mut cursor)?;
|
let msg = M::decode(&mut cursor)?;
|
||||||
let frame = Frame {
|
let frame = Frame {
|
||||||
|
|
@ -348,7 +346,7 @@ impl<M: wire::Decode> wire::Decode for Frame<M> {
|
||||||
Ok(frame)
|
Ok(frame)
|
||||||
}
|
}
|
||||||
Ok(StreamKind::Git { .. }) => {
|
Ok(StreamKind::Git { .. }) => {
|
||||||
let data = varint::payload::decode(reader)?;
|
let data = varint::payload::decode(buf)?;
|
||||||
Ok(Frame::git(stream, data))
|
Ok(Frame::git(stream, data))
|
||||||
}
|
}
|
||||||
Err(n) => Err(wire::Error::InvalidStreamKind(n)),
|
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> {
|
impl<M: wire::Encode> wire::Encode for Frame<M> {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = 0;
|
self.version.encode(buf);
|
||||||
|
self.stream.encode(buf);
|
||||||
n += self.version.encode(writer)?;
|
match &self.data {
|
||||||
n += self.stream.encode(writer)?;
|
FrameData::Control(ctrl) => ctrl.encode(buf),
|
||||||
n += match &self.data {
|
FrameData::Git(data) => varint::payload::encode(data, buf),
|
||||||
FrameData::Control(ctrl) => ctrl.encode(writer)?,
|
FrameData::Gossip(msg) => varint::payload::encode(&wire::serialize(msg), buf),
|
||||||
FrameData::Git(data) => varint::payload::encode(data, writer)?,
|
}
|
||||||
FrameData::Gossip(msg) => varint::payload::encode(&wire::serialize(msg), writer)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 cyphernet::addr::{tor, Addr, HostName, NetAddr};
|
||||||
use radicle::crypto::Signature;
|
use radicle::crypto::Signature;
|
||||||
use radicle::git::Oid;
|
use radicle::git::Oid;
|
||||||
|
|
@ -114,32 +115,28 @@ impl TryFrom<u8> for AddressType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for AnnouncementMessage {
|
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 {
|
match self {
|
||||||
Self::Node(ann) => ann.encode(writer),
|
Self::Node(ann) => ann.encode(buf),
|
||||||
Self::Inventory(ann) => ann.encode(writer),
|
Self::Inventory(ann) => ann.encode(buf),
|
||||||
Self::Refs(ann) => ann.encode(writer),
|
Self::Refs(ann) => ann.encode(buf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for RefsAnnouncement {
|
impl wire::Encode for RefsAnnouncement {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = 0;
|
self.rid.encode(buf);
|
||||||
|
self.refs.encode(buf);
|
||||||
n += self.rid.encode(writer)?;
|
self.timestamp.encode(buf);
|
||||||
n += self.refs.encode(writer)?;
|
|
||||||
n += self.timestamp.encode(writer)?;
|
|
||||||
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Decode for RefsAnnouncement {
|
impl wire::Decode for RefsAnnouncement {
|
||||||
fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
|
||||||
let rid = RepoId::decode(reader)?;
|
let rid = RepoId::decode(buf)?;
|
||||||
let refs = BoundedVec::<_, REF_REMOTE_LIMIT>::decode(reader)?;
|
let refs = BoundedVec::<_, REF_REMOTE_LIMIT>::decode(buf)?;
|
||||||
let timestamp = Timestamp::decode(reader)?;
|
let timestamp = Timestamp::decode(buf)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
rid,
|
rid,
|
||||||
|
|
@ -150,20 +147,16 @@ impl wire::Decode for RefsAnnouncement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for InventoryAnnouncement {
|
impl wire::Encode for InventoryAnnouncement {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = 0;
|
self.inventory.encode(buf);
|
||||||
|
self.timestamp.encode(buf);
|
||||||
n += self.inventory.encode(writer)?;
|
|
||||||
n += self.timestamp.encode(writer)?;
|
|
||||||
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Decode for InventoryAnnouncement {
|
impl wire::Decode for InventoryAnnouncement {
|
||||||
fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
|
||||||
let inventory = BoundedVec::decode(reader)?;
|
let inventory = BoundedVec::decode(buf)?;
|
||||||
let timestamp = Timestamp::decode(reader)?;
|
let timestamp = Timestamp::decode(buf)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inventory,
|
inventory,
|
||||||
|
|
@ -212,28 +205,25 @@ impl From<&Info> for InfoType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for Info {
|
impl wire::Encode for Info {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = 0;
|
u16::from(InfoType::from(self)).encode(buf);
|
||||||
n += u16::from(InfoType::from(self)).encode(writer)?;
|
|
||||||
match self {
|
match self {
|
||||||
Info::RefsAlreadySynced { rid, at } => {
|
Info::RefsAlreadySynced { rid, at } => {
|
||||||
n += rid.encode(writer)?;
|
rid.encode(buf);
|
||||||
n += at.encode(writer)?;
|
at.encode(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Decode for Info {
|
impl wire::Decode for Info {
|
||||||
fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
|
||||||
let info_type = reader.read_u16::<NetworkEndian>()?;
|
let info_type = buf.try_get_u16()?;
|
||||||
|
|
||||||
match InfoType::try_from(info_type) {
|
match InfoType::try_from(info_type) {
|
||||||
Ok(InfoType::RefsAlreadySynced) => {
|
Ok(InfoType::RefsAlreadySynced) => {
|
||||||
let rid = RepoId::decode(reader)?;
|
let rid = RepoId::decode(buf)?;
|
||||||
let at = Oid::decode(reader)?;
|
let at = Oid::decode(buf)?;
|
||||||
|
|
||||||
Ok(Self::RefsAlreadySynced { rid, at })
|
Ok(Self::RefsAlreadySynced { rid, at })
|
||||||
}
|
}
|
||||||
|
|
@ -243,8 +233,8 @@ impl wire::Decode for Info {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for Message {
|
impl wire::Encode for Message {
|
||||||
fn encode<W: std::io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, std::io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = self.type_id().encode(writer)?;
|
self.type_id().encode(buf);
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::Subscribe(Subscribe {
|
Self::Subscribe(Subscribe {
|
||||||
|
|
@ -252,50 +242,42 @@ impl wire::Encode for Message {
|
||||||
since,
|
since,
|
||||||
until,
|
until,
|
||||||
}) => {
|
}) => {
|
||||||
n += filter.encode(writer)?;
|
filter.encode(buf);
|
||||||
n += since.encode(writer)?;
|
since.encode(buf);
|
||||||
n += until.encode(writer)?;
|
until.encode(buf);
|
||||||
}
|
}
|
||||||
Self::Announcement(Announcement {
|
Self::Announcement(Announcement {
|
||||||
node,
|
node,
|
||||||
message,
|
message,
|
||||||
signature,
|
signature,
|
||||||
}) => {
|
}) => {
|
||||||
n += node.encode(writer)?;
|
node.encode(buf);
|
||||||
n += signature.encode(writer)?;
|
signature.encode(buf);
|
||||||
n += message.encode(writer)?;
|
message.encode(buf);
|
||||||
}
|
}
|
||||||
Self::Info(info) => {
|
Self::Info(info) => {
|
||||||
n += info.encode(writer)?;
|
info.encode(buf);
|
||||||
}
|
}
|
||||||
Self::Ping(Ping { ponglen, zeroes }) => {
|
Self::Ping(Ping { ponglen, zeroes }) => {
|
||||||
n += ponglen.encode(writer)?;
|
ponglen.encode(buf);
|
||||||
n += zeroes.encode(writer)?;
|
zeroes.encode(buf);
|
||||||
}
|
}
|
||||||
Self::Pong { zeroes } => {
|
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 {
|
impl wire::Decode for Message {
|
||||||
fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
|
||||||
let type_id = reader.read_u16::<NetworkEndian>()?;
|
let type_id = buf.try_get_u16()?;
|
||||||
|
|
||||||
match MessageType::try_from(type_id) {
|
match MessageType::try_from(type_id) {
|
||||||
Ok(MessageType::Subscribe) => {
|
Ok(MessageType::Subscribe) => {
|
||||||
let filter = Filter::decode(reader)?;
|
let filter = Filter::decode(buf)?;
|
||||||
let since = Timestamp::decode(reader)?;
|
let since = Timestamp::decode(buf)?;
|
||||||
let until = Timestamp::decode(reader)?;
|
let until = Timestamp::decode(buf)?;
|
||||||
|
|
||||||
Ok(Self::Subscribe(Subscribe {
|
Ok(Self::Subscribe(Subscribe {
|
||||||
filter,
|
filter,
|
||||||
|
|
@ -304,9 +286,9 @@ impl wire::Decode for Message {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Ok(MessageType::NodeAnnouncement) => {
|
Ok(MessageType::NodeAnnouncement) => {
|
||||||
let node = NodeId::decode(reader)?;
|
let node = NodeId::decode(buf)?;
|
||||||
let signature = Signature::decode(reader)?;
|
let signature = Signature::decode(buf)?;
|
||||||
let message = NodeAnnouncement::decode(reader)?.into();
|
let message = NodeAnnouncement::decode(buf)?.into();
|
||||||
|
|
||||||
Ok(Announcement {
|
Ok(Announcement {
|
||||||
node,
|
node,
|
||||||
|
|
@ -316,9 +298,9 @@ impl wire::Decode for Message {
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
Ok(MessageType::InventoryAnnouncement) => {
|
Ok(MessageType::InventoryAnnouncement) => {
|
||||||
let node = NodeId::decode(reader)?;
|
let node = NodeId::decode(buf)?;
|
||||||
let signature = Signature::decode(reader)?;
|
let signature = Signature::decode(buf)?;
|
||||||
let message = InventoryAnnouncement::decode(reader)?.into();
|
let message = InventoryAnnouncement::decode(buf)?.into();
|
||||||
|
|
||||||
Ok(Announcement {
|
Ok(Announcement {
|
||||||
node,
|
node,
|
||||||
|
|
@ -328,9 +310,9 @@ impl wire::Decode for Message {
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
Ok(MessageType::RefsAnnouncement) => {
|
Ok(MessageType::RefsAnnouncement) => {
|
||||||
let node = NodeId::decode(reader)?;
|
let node = NodeId::decode(buf)?;
|
||||||
let signature = Signature::decode(reader)?;
|
let signature = Signature::decode(buf)?;
|
||||||
let message = RefsAnnouncement::decode(reader)?.into();
|
let message = RefsAnnouncement::decode(buf)?.into();
|
||||||
|
|
||||||
Ok(Announcement {
|
Ok(Announcement {
|
||||||
node,
|
node,
|
||||||
|
|
@ -340,16 +322,16 @@ impl wire::Decode for Message {
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
Ok(MessageType::Info) => {
|
Ok(MessageType::Info) => {
|
||||||
let info = Info::decode(reader)?;
|
let info = Info::decode(buf)?;
|
||||||
Ok(Self::Info(info))
|
Ok(Self::Info(info))
|
||||||
}
|
}
|
||||||
Ok(MessageType::Ping) => {
|
Ok(MessageType::Ping) => {
|
||||||
let ponglen = u16::decode(reader)?;
|
let ponglen = u16::decode(buf)?;
|
||||||
let zeroes = ZeroBytes::decode(reader)?;
|
let zeroes = ZeroBytes::decode(buf)?;
|
||||||
Ok(Self::Ping(Ping { ponglen, zeroes }))
|
Ok(Self::Ping(Ping { ponglen, zeroes }))
|
||||||
}
|
}
|
||||||
Ok(MessageType::Pong) => {
|
Ok(MessageType::Pong) => {
|
||||||
let zeroes = ZeroBytes::decode(reader)?;
|
let zeroes = ZeroBytes::decode(buf)?;
|
||||||
Ok(Self::Pong { zeroes })
|
Ok(Self::Pong { zeroes })
|
||||||
}
|
}
|
||||||
Err(other) => Err(wire::Error::UnknownMessageType(other)),
|
Err(other) => Err(wire::Error::UnknownMessageType(other)),
|
||||||
|
|
@ -358,85 +340,82 @@ impl wire::Decode for Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for Address {
|
impl wire::Encode for Address {
|
||||||
fn encode<W: std::io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, std::io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = 0;
|
|
||||||
|
|
||||||
match self.host {
|
match self.host {
|
||||||
HostName::Ip(net::IpAddr::V4(ip)) => {
|
HostName::Ip(net::IpAddr::V4(ip)) => {
|
||||||
n += u8::from(AddressType::Ipv4).encode(writer)?;
|
u8::from(AddressType::Ipv4).encode(buf);
|
||||||
n += ip.octets().encode(writer)?;
|
ip.octets().encode(buf);
|
||||||
}
|
}
|
||||||
HostName::Ip(net::IpAddr::V6(ip)) => {
|
HostName::Ip(net::IpAddr::V6(ip)) => {
|
||||||
n += u8::from(AddressType::Ipv6).encode(writer)?;
|
u8::from(AddressType::Ipv6).encode(buf);
|
||||||
n += ip.octets().encode(writer)?;
|
ip.octets().encode(buf);
|
||||||
}
|
}
|
||||||
HostName::Dns(ref dns) => {
|
HostName::Dns(ref dns) => {
|
||||||
n += u8::from(AddressType::Dns).encode(writer)?;
|
u8::from(AddressType::Dns).encode(buf);
|
||||||
n += dns.encode(writer)?;
|
dns.encode(buf);
|
||||||
}
|
}
|
||||||
HostName::Tor(addr) => {
|
HostName::Tor(addr) => {
|
||||||
n += u8::from(AddressType::Onion).encode(writer)?;
|
u8::from(AddressType::Onion).encode(buf);
|
||||||
n += addr.encode(writer)?;
|
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)?;
|
self.port().encode(buf);
|
||||||
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Decode for Address {
|
impl wire::Decode for Address {
|
||||||
fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
|
||||||
let addrtype = reader.read_u8()?;
|
let addrtype = buf.try_get_u8()?;
|
||||||
|
|
||||||
let host = match AddressType::try_from(addrtype) {
|
let host = match AddressType::try_from(addrtype) {
|
||||||
Ok(AddressType::Ipv4) => {
|
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);
|
let ip = net::Ipv4Addr::from(octets);
|
||||||
|
|
||||||
HostName::Ip(net::IpAddr::V4(ip))
|
HostName::Ip(net::IpAddr::V4(ip))
|
||||||
}
|
}
|
||||||
Ok(AddressType::Ipv6) => {
|
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);
|
let ip = net::Ipv6Addr::from(octets);
|
||||||
|
|
||||||
HostName::Ip(net::IpAddr::V6(ip))
|
HostName::Ip(net::IpAddr::V6(ip))
|
||||||
}
|
}
|
||||||
Ok(AddressType::Dns) => {
|
Ok(AddressType::Dns) => {
|
||||||
let dns: String = wire::Decode::decode(reader)?;
|
let dns: String = wire::Decode::decode(buf)?;
|
||||||
|
|
||||||
HostName::Dns(dns)
|
HostName::Dns(dns)
|
||||||
}
|
}
|
||||||
Ok(AddressType::Onion) => {
|
Ok(AddressType::Onion) => {
|
||||||
let onion: tor::OnionAddrV3 = wire::Decode::decode(reader)?;
|
let onion: tor::OnionAddrV3 = wire::Decode::decode(buf)?;
|
||||||
|
|
||||||
HostName::Tor(onion)
|
HostName::Tor(onion)
|
||||||
}
|
}
|
||||||
Err(other) => return Err(wire::Error::UnknownAddressType(other)),
|
Err(other) => return Err(wire::Error::UnknownAddressType(other)),
|
||||||
};
|
};
|
||||||
let port = u16::decode(reader)?;
|
let port = u16::decode(buf)?;
|
||||||
|
|
||||||
Ok(Self::from(NetAddr { host, port }))
|
Ok(Self::from(NetAddr { host, port }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Encode for ZeroBytes {
|
impl wire::Encode for ZeroBytes {
|
||||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
fn encode(&self, buf: &mut impl BufMut) {
|
||||||
let mut n = (self.len() as u16).encode(writer)?;
|
(self.len() as u16).encode(buf);
|
||||||
for _ in 0..self.len() {
|
buf.put_bytes(0u8, self.len());
|
||||||
n += 0u8.encode(writer)?;
|
|
||||||
}
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wire::Decode for ZeroBytes {
|
impl wire::Decode for ZeroBytes {
|
||||||
fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
|
||||||
let zeroes = u16::decode(reader)?;
|
let zeroes = u16::decode(buf)?;
|
||||||
for _ in 0..zeroes {
|
for _ in 0..zeroes {
|
||||||
_ = u8::decode(reader)?;
|
_ = u8::decode(buf)?;
|
||||||
}
|
}
|
||||||
Ok(ZeroBytes::new(zeroes))
|
Ok(ZeroBytes::new(zeroes))
|
||||||
}
|
}
|
||||||
|
|
@ -508,40 +487,31 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pingpong_encode_max_size() {
|
fn test_pingpong_encode_max_size() {
|
||||||
let mut buf = Vec::new();
|
wire::serialize(&Message::Ping(Ping {
|
||||||
|
|
||||||
let ping = Message::Ping(Ping {
|
|
||||||
ponglen: 0,
|
ponglen: 0,
|
||||||
zeroes: ZeroBytes::new(Ping::MAX_PING_ZEROES),
|
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),
|
zeroes: ZeroBytes::new(Ping::MAX_PONG_ZEROES),
|
||||||
};
|
});
|
||||||
pong.encode(&mut buf)
|
|
||||||
.expect("pong should be within max message size");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pingpong_encode_size_overflow() {
|
#[should_panic(expected = "advance out of bounds")]
|
||||||
let ping = Message::Ping(Ping {
|
fn test_ping_encode_size_overflow() {
|
||||||
|
wire::serialize(&Message::Ping(Ping {
|
||||||
ponglen: 0,
|
ponglen: 0,
|
||||||
zeroes: ZeroBytes::new(Ping::MAX_PING_ZEROES + 1),
|
zeroes: ZeroBytes::new(Ping::MAX_PING_ZEROES + 1),
|
||||||
});
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
let mut buf = Vec::new();
|
#[test]
|
||||||
ping.encode(&mut buf)
|
#[should_panic(expected = "advance out of bounds")]
|
||||||
.expect_err("ping should exceed max message size");
|
fn test_pong_encode_size_overflow() {
|
||||||
|
wire::serialize(&Message::Pong {
|
||||||
let pong = Message::Pong {
|
|
||||||
zeroes: ZeroBytes::new(Ping::MAX_PONG_ZEROES + 1),
|
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]
|
#[quickcheck]
|
||||||
|
|
@ -558,7 +528,7 @@ mod tests {
|
||||||
let mut decoder = Deserializer::<1048576, Message>::new(8);
|
let mut decoder = Deserializer::<1048576, Message>::new(8);
|
||||||
|
|
||||||
for item in &items {
|
for item in &items {
|
||||||
item.encode(&mut decoder).unwrap();
|
item.encode(&mut decoder);
|
||||||
}
|
}
|
||||||
for item in items {
|
for item in items {
|
||||||
assert_eq!(decoder.next().unwrap().unwrap(), item);
|
assert_eq!(decoder.next().unwrap().unwrap(), item);
|
||||||
|
|
@ -570,14 +540,26 @@ mod tests {
|
||||||
.quickcheck(property as fn(items: Vec<Message>));
|
.quickcheck(property as fn(items: Vec<Message>));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[quickcheck]
|
#[test]
|
||||||
fn prop_zero_bytes_encode_decode(zeroes: ZeroBytes) {
|
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!(
|
assert_eq!(
|
||||||
wire::deserialize::<ZeroBytes>(&wire::serialize(&zeroes)).unwrap(),
|
wire::deserialize::<ZeroBytes>(&wire::serialize(&zeroes)).unwrap(),
|
||||||
zeroes
|
zeroes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qcheck::QuickCheck::new()
|
||||||
|
.gen(qcheck::Gen::new(16))
|
||||||
|
.quickcheck(property as fn(zeroes: wire::Size));
|
||||||
|
}
|
||||||
|
|
||||||
#[quickcheck]
|
#[quickcheck]
|
||||||
fn prop_addr(addr: Address) {
|
fn prop_addr(addr: Address) {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
// This implementation is largely based on the `quinn` crate.
|
// This implementation is largely based on the `quinn` crate.
|
||||||
// Copyright (c) 2018 The quinn developers.
|
// 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 thiserror::Error;
|
||||||
|
|
||||||
use crate::wire;
|
use crate::wire;
|
||||||
|
|
@ -44,6 +44,10 @@ impl VarInt {
|
||||||
Err(BoundsExceeded)
|
Err(BoundsExceeded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_unchecked(x: u64) -> Self {
|
||||||
|
Self(x)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Deref for VarInt {
|
impl ops::Deref for VarInt {
|
||||||
|
|
@ -98,27 +102,27 @@ impl fmt::Display for VarInt {
|
||||||
pub struct BoundsExceeded;
|
pub struct BoundsExceeded;
|
||||||
|
|
||||||
impl Decode for VarInt {
|
impl Decode for VarInt {
|
||||||
fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, wire::Error> {
|
fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
|
||||||
let mut buf = [0; 8];
|
let mut tmp = [0; 8];
|
||||||
buf[0] = r.read_u8()?;
|
tmp[0] = buf.try_get_u8()?;
|
||||||
|
|
||||||
// Integer length.
|
// Integer length.
|
||||||
let tag = buf[0] >> 6;
|
let tag = tmp[0] >> 6;
|
||||||
buf[0] &= 0b0011_1111;
|
tmp[0] &= 0b0011_1111;
|
||||||
|
|
||||||
let x = match tag {
|
let x = match tag {
|
||||||
0b00 => u64::from(buf[0]),
|
0b00 => u64::from(tmp[0]),
|
||||||
0b01 => {
|
0b01 => {
|
||||||
r.read_exact(&mut buf[1..2])?;
|
buf.try_copy_to_slice(&mut tmp[1..2])?;
|
||||||
u64::from(u16::from_be_bytes([buf[0], buf[1]]))
|
u64::from(u16::from_be_bytes([tmp[0], tmp[1]]))
|
||||||
}
|
}
|
||||||
0b10 => {
|
0b10 => {
|
||||||
r.read_exact(&mut buf[1..4])?;
|
buf.try_copy_to_slice(&mut tmp[1..4])?;
|
||||||
u64::from(u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]))
|
u64::from(u32::from_be_bytes([tmp[0], tmp[1], tmp[2], tmp[3]]))
|
||||||
}
|
}
|
||||||
0b11 => {
|
0b11 => {
|
||||||
r.read_exact(&mut buf[1..8])?;
|
buf.try_copy_to_slice(&mut tmp[1..8])?;
|
||||||
u64::from_be_bytes(buf)
|
u64::from_be_bytes(tmp)
|
||||||
}
|
}
|
||||||
// SAFETY: It should be obvious that we can't have any other bit pattern
|
// SAFETY: It should be obvious that we can't have any other bit pattern
|
||||||
// than the above, since all other bits are zeroed.
|
// than the above, since all other bits are zeroed.
|
||||||
|
|
@ -129,7 +133,7 @@ impl Decode for VarInt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encode 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;
|
let x: u64 = self.0;
|
||||||
|
|
||||||
if x < 2u64.pow(6) {
|
if x < 2u64.pow(6) {
|
||||||
|
|
@ -151,25 +155,19 @@ pub mod payload {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Encode varint-prefixed data payload.
|
/// Encode varint-prefixed data payload.
|
||||||
pub fn encode<W: io::Write + ?Sized>(payload: &[u8], writer: &mut W) -> io::Result<usize> {
|
pub fn encode(payload: &[u8], buf: &mut impl BufMut) {
|
||||||
let mut n = 0;
|
|
||||||
let len = payload.len();
|
let len = payload.len();
|
||||||
let varint =
|
let varint = VarInt::new_unchecked(len as u64);
|
||||||
VarInt::new(len as u64).map_err(|_| io::Error::from(io::ErrorKind::InvalidInput))?;
|
|
||||||
|
|
||||||
n += varint.encode(writer)?; // The length of the payload length.
|
varint.encode(buf); // The length of the payload length.
|
||||||
n += len; // The length of the data payload itself.
|
buf.put_slice(payload);
|
||||||
|
|
||||||
writer.write_all(payload)?;
|
|
||||||
|
|
||||||
Ok(n)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decode varint-prefixed data payload.
|
/// Decode varint-prefixed data payload.
|
||||||
pub fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Vec<u8>, wire::Error> {
|
pub fn decode(buf: &mut impl Buf) -> Result<Vec<u8>, wire::Error> {
|
||||||
let size = VarInt::decode(reader)?;
|
let size = VarInt::decode(buf)?;
|
||||||
let mut data = vec![0; *size as usize];
|
let mut data = vec![0; *size as usize];
|
||||||
reader.read_exact(&mut data[..])?;
|
buf.try_copy_to_slice(&mut data[..])?;
|
||||||
|
|
||||||
Ok(data)
|
Ok(data)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ edition.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = { workspace = true }
|
byteorder = "1.4"
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
zeroize = { workspace = true }
|
zeroize = { workspace = true }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue