Use bytes crate for zerocopy and memory re-use (#182)

* Use bytes. Not yet zerocopy everywhere but compiles

* Actually zerocopy

* Actually zerocopy

* Not actually storing the torrent on disk now
This commit is contained in:
Igor Katson 2024-08-14 12:08:46 +01:00 committed by GitHub
parent 3cc9e444b1
commit c7ed475f54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 182 additions and 95 deletions

8
Cargo.lock generated
View file

@ -1363,6 +1363,7 @@ name = "librqbit-bencode"
version = "2.2.3" version = "2.2.3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes",
"librqbit-buffers", "librqbit-buffers",
"librqbit-clone-to-owned", "librqbit-clone-to-owned",
"librqbit-sha1-wrapper", "librqbit-sha1-wrapper",
@ -1373,6 +1374,7 @@ dependencies = [
name = "librqbit-buffers" name = "librqbit-buffers"
version = "3.0.1" version = "3.0.1"
dependencies = [ dependencies = [
"bytes",
"librqbit-clone-to-owned", "librqbit-clone-to-owned",
"serde", "serde",
] ]
@ -1380,12 +1382,16 @@ dependencies = [
[[package]] [[package]]
name = "librqbit-clone-to-owned" name = "librqbit-clone-to-owned"
version = "2.2.1" version = "2.2.1"
dependencies = [
"bytes",
]
[[package]] [[package]]
name = "librqbit-core" name = "librqbit-core"
version = "3.9.0" version = "3.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes",
"data-encoding", "data-encoding",
"directories", "directories",
"hex 0.4.3", "hex 0.4.3",
@ -1409,6 +1415,7 @@ version = "5.0.4"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"backoff", "backoff",
"bytes",
"chrono", "chrono",
"dashmap", "dashmap",
"futures", "futures",
@ -1437,6 +1444,7 @@ dependencies = [
"bincode", "bincode",
"bitvec", "bitvec",
"byteorder", "byteorder",
"bytes",
"librqbit-bencode", "librqbit-bencode",
"librqbit-buffers", "librqbit-buffers",
"librqbit-clone-to-owned", "librqbit-clone-to-owned",

View file

@ -16,3 +16,4 @@ buffers = { path = "../buffers", package = "librqbit-buffers", version = "3.0.1"
clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "2.2.1" } clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "2.2.1" }
anyhow = "1" anyhow = "1"
sha1w = { path = "../sha1w", default-features = false, package = "librqbit-sha1-wrapper", version = "3.0.0" } sha1w = { path = "../sha1w", default-features = false, package = "librqbit-sha1-wrapper", version = "3.0.0" }
bytes = "1.7.1"

View file

@ -1,6 +1,7 @@
use std::{collections::HashMap, marker::PhantomData}; use std::{collections::HashMap, marker::PhantomData};
use buffers::{ByteBuf, ByteBufOwned}; use buffers::{ByteBuf, ByteBufOwned};
use bytes::Bytes;
use clone_to_owned::CloneToOwned; use clone_to_owned::CloneToOwned;
use serde::Deserializer; use serde::Deserializer;
@ -122,12 +123,12 @@ where
{ {
type Target = BencodeValue<<BufT as CloneToOwned>::Target>; type Target = BencodeValue<<BufT as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
match self { match self {
BencodeValue::Bytes(b) => BencodeValue::Bytes(b.clone_to_owned()), BencodeValue::Bytes(b) => BencodeValue::Bytes(b.clone_to_owned(within_buffer)),
BencodeValue::Integer(i) => BencodeValue::Integer(*i), BencodeValue::Integer(i) => BencodeValue::Integer(*i),
BencodeValue::List(l) => BencodeValue::List(l.clone_to_owned()), BencodeValue::List(l) => BencodeValue::List(l.clone_to_owned(within_buffer)),
BencodeValue::Dict(d) => BencodeValue::Dict(d.clone_to_owned()), BencodeValue::Dict(d) => BencodeValue::Dict(d.clone_to_owned(within_buffer)),
} }
} }
} }

View file

@ -12,3 +12,4 @@ readme = "README.md"
[dependencies] [dependencies]
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "2.2.1" } clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "2.2.1" }
bytes = "1"

View file

@ -3,12 +3,13 @@
// //
// Not useful outside of librqbit. // Not useful outside of librqbit.
use bytes::Bytes;
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use clone_to_owned::CloneToOwned; use clone_to_owned::CloneToOwned;
#[derive(Default, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)] #[derive(Default, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
pub struct ByteBufOwned(pub Box<[u8]>); pub struct ByteBufOwned(pub bytes::Bytes);
#[derive(Default, Deserialize, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)] #[derive(Default, Deserialize, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
#[serde(transparent)] #[serde(transparent)]
@ -90,15 +91,30 @@ impl std::fmt::Display for ByteBufOwned {
impl<'a> CloneToOwned for ByteBuf<'a> { impl<'a> CloneToOwned for ByteBuf<'a> {
type Target = ByteBufOwned; type Target = ByteBufOwned;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
ByteBufOwned(self.as_slice().to_owned().into_boxed_slice()) // Try zero-copy from the provided buffer.
if let Some(within_buffer) = within_buffer {
let haystack = within_buffer.as_ptr() as usize;
let haystack_end = haystack + within_buffer.len();
let needle = self.0.as_ptr() as usize;
let needle_end = needle + self.0.len();
if needle >= haystack && needle_end <= haystack_end {
return ByteBufOwned(within_buffer.slice_ref(self.0.as_ref()));
} else {
#[cfg(debug_assertions)]
panic!("bug: broken buffers! not inside within_buffer");
}
}
ByteBufOwned(Bytes::copy_from_slice(self.0))
} }
} }
impl CloneToOwned for ByteBufOwned { impl CloneToOwned for ByteBufOwned {
type Target = ByteBufOwned; type Target = ByteBufOwned;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, _within_buffer: Option<&Bytes>) -> Self::Target {
ByteBufOwned(self.0.clone()) ByteBufOwned(self.0.clone())
} }
} }
@ -139,13 +155,19 @@ impl<'a> From<&'a [u8]> for ByteBuf<'a> {
impl<'a> From<&'a [u8]> for ByteBufOwned { impl<'a> From<&'a [u8]> for ByteBufOwned {
fn from(b: &'a [u8]) -> Self { fn from(b: &'a [u8]) -> Self {
Self(b.into()) Self(b.to_owned().into())
} }
} }
impl From<Vec<u8>> for ByteBufOwned { impl From<Vec<u8>> for ByteBufOwned {
fn from(b: Vec<u8>) -> Self { fn from(b: Vec<u8>) -> Self {
Self(b.into_boxed_slice()) Self(b.into())
}
}
impl From<Bytes> for ByteBufOwned {
fn from(b: Bytes) -> Self {
Self(b)
} }
} }

View file

@ -10,3 +10,4 @@ readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
bytes = "1.7.1"

View file

@ -6,12 +6,13 @@
// This lets us express types like TorrentMetaInfo<&[u8]> for zero-copy metadata about a bencode buffer in memory, // This lets us express types like TorrentMetaInfo<&[u8]> for zero-copy metadata about a bencode buffer in memory,
// but to have one-line conversion for it into TorrentMetaInfo<Vec<u8>> so that we can store it later somewhere. // but to have one-line conversion for it into TorrentMetaInfo<Vec<u8>> so that we can store it later somewhere.
use bytes::Bytes;
use std::collections::HashMap; use std::collections::HashMap;
pub trait CloneToOwned { pub trait CloneToOwned {
type Target; type Target;
fn clone_to_owned(&self) -> Self::Target; fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target;
} }
impl<T> CloneToOwned for Option<T> impl<T> CloneToOwned for Option<T>
@ -20,8 +21,8 @@ where
{ {
type Target = Option<<T as CloneToOwned>::Target>; type Target = Option<<T as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
self.as_ref().map(|i| i.clone_to_owned()) self.as_ref().map(|i| i.clone_to_owned(within_buffer))
} }
} }
@ -31,15 +32,17 @@ where
{ {
type Target = Vec<<T as CloneToOwned>::Target>; type Target = Vec<<T as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
self.iter().map(|i| i.clone_to_owned()).collect() self.iter()
.map(|i| i.clone_to_owned(within_buffer))
.collect()
} }
} }
impl CloneToOwned for u8 { impl CloneToOwned for u8 {
type Target = u8; type Target = u8;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, _within_buffer: Option<&Bytes>) -> Self::Target {
*self *self
} }
} }
@ -47,7 +50,7 @@ impl CloneToOwned for u8 {
impl CloneToOwned for u32 { impl CloneToOwned for u32 {
type Target = u32; type Target = u32;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, _within_buffer: Option<&Bytes>) -> Self::Target {
*self *self
} }
} }
@ -60,10 +63,13 @@ where
{ {
type Target = HashMap<<K as CloneToOwned>::Target, <V as CloneToOwned>::Target>; type Target = HashMap<<K as CloneToOwned>::Target, <V as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
let mut result = HashMap::with_capacity(self.capacity()); let mut result = HashMap::with_capacity(self.capacity());
for (k, v) in self { for (k, v) in self {
result.insert(k.clone_to_owned(), v.clone_to_owned()); result.insert(
k.clone_to_owned(within_buffer),
v.clone_to_owned(within_buffer),
);
} }
result result
} }

View file

@ -35,6 +35,7 @@ clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owne
librqbit-core = { path = "../librqbit_core", version = "3.9.0" } librqbit-core = { path = "../librqbit_core", version = "3.9.0" }
chrono = { version = "0.4.31", features = ["serde"] } chrono = { version = "0.4.31", features = ["serde"] }
tokio-util = "0.7.10" tokio-util = "0.7.10"
bytes = "1.7.1"
[dev-dependencies] [dev-dependencies]
tracing-subscriber = "0.3" tracing-subscriber = "0.3"

View file

@ -5,6 +5,7 @@ use std::{
}; };
use bencode::{ByteBuf, ByteBufOwned}; use bencode::{ByteBuf, ByteBufOwned};
use bytes::Bytes;
use clone_to_owned::CloneToOwned; use clone_to_owned::CloneToOwned;
use librqbit_core::hash_id::Id20; use librqbit_core::hash_id::Id20;
use serde::{ use serde::{
@ -73,10 +74,10 @@ where
{ {
type Target = ErrorDescription<<BufT as CloneToOwned>::Target>; type Target = ErrorDescription<<BufT as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
ErrorDescription { ErrorDescription {
code: self.code, code: self.code,
description: self.description.clone_to_owned(), description: self.description.clone_to_owned(within_buffer),
} }
} }
} }

View file

@ -382,7 +382,7 @@ impl<H: PeerConnectionHandler> PeerConnection<H> {
trace!("received: {:?}", &message); trace!("received: {:?}", &message);
if let Message::Extended(ExtendedMessage::Handshake(h)) = &message { if let Message::Extended(ExtendedMessage::Handshake(h)) = &message {
*extended_handshake_ref.write() = Some(h.clone_to_owned()); *extended_handshake_ref.write() = Some(h.clone_to_owned(None));
self.handler.on_extended_handshake(h)?; self.handler.on_extended_handshake(h)?;
trace!("remembered extended handshake for future serializing"); trace!("remembered extended handshake for future serializing");
} else { } else {

View file

@ -2,6 +2,7 @@ use std::{net::SocketAddr, sync::Arc};
use bencode::from_bytes; use bencode::from_bytes;
use buffers::{ByteBuf, ByteBufOwned}; use buffers::{ByteBuf, ByteBufOwned};
use bytes::Bytes;
use librqbit_core::{ use librqbit_core::{
constants::CHUNK_SIZE, constants::CHUNK_SIZE,
hash_id::Id20, hash_id::Id20,
@ -178,9 +179,14 @@ impl PeerConnectionHandler for Handler {
.unwrap() .unwrap()
.record_piece(piece, &data, self.info_hash)?; .record_piece(piece, &data, self.info_hash)?;
if piece_ready { if piece_ready {
let buf = self.locked.write().take().unwrap().buffer; let buf = Bytes::from(self.locked.write().take().unwrap().buffer);
let info = from_bytes::<TorrentMetaV1Info<ByteBufOwned>>(&buf); let info = from_bytes::<TorrentMetaV1Info<ByteBuf>>(&buf)
let info = info.map(|i| (i, ByteBufOwned(buf.into_boxed_slice()))); .map(|i| {
use clone_to_owned::CloneToOwned;
i.clone_to_owned(Some(&buf))
})
.map(|i| (i, ByteBufOwned(buf)));
self.result_tx self.result_tx
.lock() .lock()
.take() .take()

View file

@ -45,7 +45,8 @@ use librqbit_core::{
peer_id::generate_peer_id, peer_id::generate_peer_id,
spawn_utils::spawn_with_cancel, spawn_utils::spawn_with_cancel,
torrent_metainfo::{ torrent_metainfo::{
torrent_from_bytes as bencode_torrent_from_bytes, TorrentMetaV1Info, TorrentMetaV1Owned, torrent_from_bytes as bencode_torrent_from_bytes, TorrentMetaV1Borrowed, TorrentMetaV1Info,
TorrentMetaV1Owned,
}, },
}; };
use parking_lot::RwLock; use parking_lot::RwLock;
@ -61,7 +62,7 @@ pub const SUPPORTED_SCHEMES: [&str; 3] = ["http:", "https:", "magnet:"];
pub type TorrentId = usize; pub type TorrentId = usize;
fn torrent_from_bytes(bytes: &[u8]) -> anyhow::Result<TorrentMetaV1Owned> { fn torrent_from_bytes(bytes: &[u8]) -> anyhow::Result<TorrentMetaV1Borrowed> {
debug!( debug!(
"all fields in torrent: {:#?}", "all fields in torrent: {:#?}",
bencode::dyn_from_bytes::<ByteBuf>(bytes) bencode::dyn_from_bytes::<ByteBuf>(bytes)
@ -120,7 +121,11 @@ impl SessionDatabase {
.map(|u| u.to_string()) .map(|u| u.to_string())
.collect(), .collect(),
info_hash: torrent.info_hash().as_string(), info_hash: torrent.info_hash().as_string(),
torrent_bytes: torrent.info.torrent_bytes.clone(), // TODO: this could take up too much space / time / resources to write on interval.
// Store this outside the JSON file
//
// torrent_bytes: torrent.info.torrent_bytes.clone(),
torrent_bytes: Bytes::new(),
info: torrent.info().info.clone(), info: torrent.info().info.clone(),
only_files: torrent.only_files().clone(), only_files: torrent.only_files().clone(),
is_paused: torrent is_paused: torrent
@ -251,8 +256,10 @@ async fn torrent_from_url(
.await .await
.with_context(|| format!("error reading response body from {url}"))?; .with_context(|| format!("error reading response body from {url}"))?;
Ok(( Ok((
torrent_from_bytes(&b).context("error decoding torrent")?, torrent_from_bytes(&b)
b.to_vec().into(), .context("error decoding torrent")?
.clone_to_owned(Some(&b)),
b.into(),
)) ))
} }
@ -415,7 +422,7 @@ pub fn read_local_file_including_stdin(filename: &str) -> anyhow::Result<Vec<u8>
pub enum AddTorrent<'a> { pub enum AddTorrent<'a> {
Url(Cow<'a, str>), Url(Cow<'a, str>),
TorrentFileBytes(Cow<'a, [u8]>), TorrentFileBytes(Cow<'a, [u8]>),
TorrentInfo(Box<TorrentMetaV1Owned>), TorrentInfo(Box<TorrentMetaV1Owned>, Bytes),
} }
impl<'a> AddTorrent<'a> { impl<'a> AddTorrent<'a> {
@ -448,7 +455,7 @@ impl<'a> AddTorrent<'a> {
match self { match self {
Self::Url(s) => s.into_owned().into_bytes(), Self::Url(s) => s.into_owned().into_bytes(),
Self::TorrentFileBytes(b) => b.into_owned(), Self::TorrentFileBytes(b) => b.into_owned(),
Self::TorrentInfo(_) => unimplemented!(), Self::TorrentInfo(..) => unimplemented!(),
} }
} }
} }
@ -752,7 +759,7 @@ impl Session {
} }
}; };
let handshake = h.clone_to_owned(); let handshake = h.clone_to_owned(None);
return Ok(( return Ok((
live, live,
@ -877,24 +884,42 @@ impl Session {
.into_iter() .into_iter()
.map(|t| ByteBufOwned::from(t.into_bytes())) .map(|t| ByteBufOwned::from(t.into_bytes()))
.collect(); .collect();
let info = TorrentMetaV1Owned {
announce: trackers.first().cloned(), let torrent_bytes = storrent.torrent_bytes;
announce_list: vec![trackers],
info: storrent.info, let info = if !torrent_bytes.is_empty() {
comment: None, torrent_from_bytes(&torrent_bytes)
created_by: None, .map(|t| t.clone_to_owned(Some(&torrent_bytes)))
encoding: None, .ok()
publisher: None, } else {
publisher_url: None, None
creation_date: None,
info_hash: Id20::from_str(&storrent.info_hash)?,
}; };
let info = match info {
Some(info) => info,
None => {
let info_hash = Id20::from_str(&storrent.info_hash)?;
debug!(?info_hash, "torrent added before 6.1.0, need to readd");
TorrentMetaV1Owned {
announce: trackers.first().cloned(),
announce_list: vec![trackers],
info: storrent.info,
comment: None,
created_by: None,
encoding: None,
publisher: None,
publisher_url: None,
creation_date: None,
info_hash,
}
}
};
futures.push({ futures.push({
let session = self.clone(); let session = self.clone();
async move { async move {
session session
.add_torrent( .add_torrent(
AddTorrent::TorrentInfo(Box::new(info)), AddTorrent::TorrentInfo(Box::new(info), torrent_bytes),
Some(AddTorrentOptions { Some(AddTorrentOptions {
paused: storrent.is_paused, paused: storrent.is_paused,
output_folder: Some( output_folder: Some(
@ -1041,14 +1066,19 @@ impl Session {
url url
) )
} }
AddTorrent::TorrentFileBytes(bytes) => ( AddTorrent::TorrentFileBytes(bytes) => {
torrent_from_bytes(&bytes).context("error decoding torrent")?, let bytes = match bytes {
ByteBufOwned::from(bytes.into_owned()), Cow::Borrowed(b) => ::bytes::Bytes::copy_from_slice(b),
), Cow::Owned(v) => ::bytes::Bytes::from(v),
AddTorrent::TorrentInfo(t) => { };
// TODO: this is lossy, as we don't store the bytes. (
(*t, ByteBufOwned(Vec::new().into_boxed_slice())) torrent_from_bytes(&bytes)
.map(|t| t.clone_to_owned(Some(&bytes)))
.context("error decoding torrent")?,
ByteBufOwned(bytes),
)
} }
AddTorrent::TorrentInfo(t, bytes) => (*t, bytes.into()),
}; };
let trackers = torrent let trackers = torrent
@ -1081,7 +1111,7 @@ impl Session {
InternalAddResult { InternalAddResult {
info_hash: torrent.info_hash, info_hash: torrent.info_hash,
info: torrent.info, info: torrent.info,
torrent_bytes: Bytes::from(bytes.0), torrent_bytes: bytes.0,
trackers, trackers,
peer_rx, peer_rx,
initial_peers: opts initial_peers: opts

View file

@ -779,7 +779,7 @@ impl<'a> PeerConnectionHandler for &'a PeerHandler {
.context("on_download_request")?; .context("on_download_request")?;
} }
Message::Bitfield(b) => self Message::Bitfield(b) => self
.on_bitfield(b.clone_to_owned()) .on_bitfield(b.clone_to_owned(None))
.context("on_bitfield")?, .context("on_bitfield")?,
Message::Choke => self.on_i_am_choked(), Message::Choke => self.on_i_am_choked(),
Message::Unchoke => self.on_i_am_unchoked(), Message::Unchoke => self.on_i_am_unchoked(),
@ -1127,7 +1127,7 @@ impl PeerHandler {
} }
self.state self.state
.peers .peers
.update_bitfield_from_vec(self.addr, bitfield.0); .update_bitfield_from_vec(self.addr, bitfield.0.to_vec().into_boxed_slice());
self.on_bitfield_notify.notify_waiters(); self.on_bitfield_notify.notify_waiters();
Ok(()) Ok(())
} }
@ -1480,7 +1480,7 @@ impl PeerHandler {
let state = self.state.clone(); let state = self.state.clone();
let addr = self.addr; let addr = self.addr;
let counters = self.counters.clone(); let counters = self.counters.clone();
let piece = piece.clone_to_owned(); let piece = piece.clone_to_owned(None);
let tx = self.tx.clone(); let tx = self.tx.clone();
let span = tracing::error_span!("deferred_write"); let span = tracing::error_span!("deferred_write");

View file

@ -26,6 +26,7 @@ itertools = "0.12"
directories = "5" directories = "5"
tokio-util = "0.7.10" tokio-util = "0.7.10"
data-encoding = "2.6.0" data-encoding = "2.6.0"
bytes = "1.7.1"
[dev-dependencies] [dev-dependencies]

View file

@ -1,11 +1,11 @@
use std::{iter::once, path::PathBuf};
use anyhow::Context; use anyhow::Context;
use bencode::BencodeDeserializer; use bencode::BencodeDeserializer;
use buffers::{ByteBuf, ByteBufOwned}; use buffers::{ByteBuf, ByteBufOwned};
use bytes::Bytes;
use clone_to_owned::CloneToOwned; use clone_to_owned::CloneToOwned;
use itertools::Either; use itertools::Either;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{iter::once, path::PathBuf};
use crate::{hash_id::Id20, lengths::Lengths}; use crate::{hash_id::Id20, lengths::Lengths};
@ -274,10 +274,10 @@ where
{ {
type Target = TorrentMetaV1File<<BufType as CloneToOwned>::Target>; type Target = TorrentMetaV1File<<BufType as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
TorrentMetaV1File { TorrentMetaV1File {
length: self.length, length: self.length,
path: self.path.clone_to_owned(), path: self.path.clone_to_owned(within_buffer),
} }
} }
} }
@ -288,14 +288,14 @@ where
{ {
type Target = TorrentMetaV1Info<<BufType as CloneToOwned>::Target>; type Target = TorrentMetaV1Info<<BufType as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
TorrentMetaV1Info { TorrentMetaV1Info {
name: self.name.clone_to_owned(), name: self.name.clone_to_owned(within_buffer),
pieces: self.pieces.clone_to_owned(), pieces: self.pieces.clone_to_owned(within_buffer),
piece_length: self.piece_length, piece_length: self.piece_length,
length: self.length, length: self.length,
md5sum: self.md5sum.clone_to_owned(), md5sum: self.md5sum.clone_to_owned(within_buffer),
files: self.files.clone_to_owned(), files: self.files.clone_to_owned(within_buffer),
} }
} }
} }
@ -306,16 +306,16 @@ where
{ {
type Target = TorrentMetaV1<<BufType as CloneToOwned>::Target>; type Target = TorrentMetaV1<<BufType as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
TorrentMetaV1 { TorrentMetaV1 {
announce: self.announce.clone_to_owned(), announce: self.announce.clone_to_owned(within_buffer),
announce_list: self.announce_list.clone_to_owned(), announce_list: self.announce_list.clone_to_owned(within_buffer),
info: self.info.clone_to_owned(), info: self.info.clone_to_owned(within_buffer),
comment: self.comment.clone_to_owned(), comment: self.comment.clone_to_owned(within_buffer),
created_by: self.created_by.clone_to_owned(), created_by: self.created_by.clone_to_owned(within_buffer),
encoding: self.encoding.clone_to_owned(), encoding: self.encoding.clone_to_owned(within_buffer),
publisher: self.publisher.clone_to_owned(), publisher: self.publisher.clone_to_owned(within_buffer),
publisher_url: self.publisher_url.clone_to_owned(), publisher_url: self.publisher_url.clone_to_owned(within_buffer),
creation_date: self.creation_date, creation_date: self.creation_date,
info_hash: self.info_hash, info_hash: self.info_hash,
} }

View file

@ -20,3 +20,4 @@ clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owne
librqbit-core = { path = "../librqbit_core", version = "3.9.0" } librqbit-core = { path = "../librqbit_core", version = "3.9.0" }
bitvec = "1" bitvec = "1"
anyhow = "1" anyhow = "1"
bytes = "1.7.1"

View file

@ -6,6 +6,7 @@ use std::{
use buffers::ByteBuf; use buffers::ByteBuf;
use byteorder::ByteOrder; use byteorder::ByteOrder;
use byteorder::BE; use byteorder::BE;
use bytes::Bytes;
use clone_to_owned::CloneToOwned; use clone_to_owned::CloneToOwned;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
@ -75,14 +76,14 @@ where
{ {
type Target = ExtendedHandshake<<ByteBuf as CloneToOwned>::Target>; type Target = ExtendedHandshake<<ByteBuf as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
ExtendedHandshake { ExtendedHandshake {
m: self.m.clone_to_owned(), m: self.m.clone_to_owned(within_buffer),
p: self.p, p: self.p,
v: self.v.clone_to_owned(), v: self.v.clone_to_owned(within_buffer),
yourip: self.yourip, yourip: self.yourip,
ipv6: self.ipv6.clone_to_owned(), ipv6: self.ipv6.clone_to_owned(within_buffer),
ipv4: self.ipv4.clone_to_owned(), ipv4: self.ipv4.clone_to_owned(within_buffer),
reqq: self.reqq, reqq: self.reqq,
metadata_size: self.metadata_size, metadata_size: self.metadata_size,
complete_ago: self.complete_ago, complete_ago: self.complete_ago,

View file

@ -1,6 +1,7 @@
use bencode::bencode_serialize_to_writer; use bencode::bencode_serialize_to_writer;
use bencode::from_bytes; use bencode::from_bytes;
use bencode::BencodeValue; use bencode::BencodeValue;
use bytes::Bytes;
use clone_to_owned::CloneToOwned; use clone_to_owned::CloneToOwned;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -27,11 +28,15 @@ where
{ {
type Target = ExtendedMessage<<ByteBuf as CloneToOwned>::Target>; type Target = ExtendedMessage<<ByteBuf as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
match self { match self {
ExtendedMessage::Handshake(h) => ExtendedMessage::Handshake(h.clone_to_owned()), ExtendedMessage::Handshake(h) => {
ExtendedMessage::Dyn(u, d) => ExtendedMessage::Dyn(*u, d.clone_to_owned()), ExtendedMessage::Handshake(h.clone_to_owned(within_buffer))
ExtendedMessage::UtMetadata(m) => ExtendedMessage::UtMetadata(m.clone_to_owned()), }
ExtendedMessage::Dyn(u, d) => ExtendedMessage::Dyn(*u, d.clone_to_owned(within_buffer)),
ExtendedMessage::UtMetadata(m) => {
ExtendedMessage::UtMetadata(m.clone_to_owned(within_buffer))
}
} }
} }
} }

View file

@ -1,10 +1,10 @@
use std::io::Write;
use bencode::bencode_serialize_to_writer; use bencode::bencode_serialize_to_writer;
use bencode::BencodeDeserializer; use bencode::BencodeDeserializer;
use bytes::Bytes;
use clone_to_owned::CloneToOwned; use clone_to_owned::CloneToOwned;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use std::io::Write;
use crate::MessageDeserializeError; use crate::MessageDeserializeError;
@ -22,7 +22,7 @@ pub enum UtMetadata<ByteBuf> {
impl<ByteBuf: CloneToOwned> CloneToOwned for UtMetadata<ByteBuf> { impl<ByteBuf: CloneToOwned> CloneToOwned for UtMetadata<ByteBuf> {
type Target = UtMetadata<<ByteBuf as CloneToOwned>::Target>; type Target = UtMetadata<<ByteBuf as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
match self { match self {
UtMetadata::Request(req) => UtMetadata::Request(*req), UtMetadata::Request(req) => UtMetadata::Request(*req),
UtMetadata::Data { UtMetadata::Data {
@ -32,7 +32,7 @@ impl<ByteBuf: CloneToOwned> CloneToOwned for UtMetadata<ByteBuf> {
} => UtMetadata::Data { } => UtMetadata::Data {
piece: *piece, piece: *piece,
total_size: *total_size, total_size: *total_size,
data: data.clone_to_owned(), data: data.clone_to_owned(within_buffer),
}, },
UtMetadata::Reject(piece) => UtMetadata::Reject(*piece), UtMetadata::Reject(piece) => UtMetadata::Reject(*piece),
} }

View file

@ -7,6 +7,7 @@ pub mod extended;
use bincode::Options; use bincode::Options;
use buffers::{ByteBuf, ByteBufOwned}; use buffers::{ByteBuf, ByteBufOwned};
use byteorder::{ByteOrder, BE}; use byteorder::{ByteOrder, BE};
use bytes::Bytes;
use clone_to_owned::CloneToOwned; use clone_to_owned::CloneToOwned;
use librqbit_core::{constants::CHUNK_SIZE, hash_id::Id20, lengths::ChunkInfo}; use librqbit_core::{constants::CHUNK_SIZE, hash_id::Id20, lengths::ChunkInfo};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -84,11 +85,11 @@ pub struct Piece<B> {
impl<B: CloneToOwned> CloneToOwned for Piece<B> { impl<B: CloneToOwned> CloneToOwned for Piece<B> {
type Target = Piece<B::Target>; type Target = Piece<B::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
Piece { Piece {
index: self.index, index: self.index,
begin: self.begin, begin: self.begin,
block: self.block.clone_to_owned(), block: self.block.clone_to_owned(within_buffer),
} }
} }
} }
@ -211,23 +212,23 @@ where
{ {
type Target = Message<<ByteBuf as CloneToOwned>::Target>; type Target = Message<<ByteBuf as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
match self { match self {
Message::Request(req) => Message::Request(*req), Message::Request(req) => Message::Request(*req),
Message::Cancel(req) => Message::Cancel(*req), Message::Cancel(req) => Message::Cancel(*req),
Message::Bitfield(b) => Message::Bitfield(b.clone_to_owned()), Message::Bitfield(b) => Message::Bitfield(b.clone_to_owned(within_buffer)),
Message::Choke => Message::Choke, Message::Choke => Message::Choke,
Message::Unchoke => Message::Unchoke, Message::Unchoke => Message::Unchoke,
Message::Interested => Message::Interested, Message::Interested => Message::Interested,
Message::Piece(piece) => Message::Piece(Piece { Message::Piece(piece) => Message::Piece(Piece {
index: piece.index, index: piece.index,
begin: piece.begin, begin: piece.begin,
block: piece.block.clone_to_owned(), block: piece.block.clone_to_owned(within_buffer),
}), }),
Message::KeepAlive => Message::KeepAlive, Message::KeepAlive => Message::KeepAlive,
Message::Have(v) => Message::Have(*v), Message::Have(v) => Message::Have(*v),
Message::NotInterested => Message::NotInterested, Message::NotInterested => Message::NotInterested,
Message::Extended(e) => Message::Extended(e.clone_to_owned()), Message::Extended(e) => Message::Extended(e.clone_to_owned(within_buffer)),
} }
} }
} }
@ -585,9 +586,9 @@ where
{ {
type Target = Handshake<<B as CloneToOwned>::Target>; type Target = Handshake<<B as CloneToOwned>::Target>;
fn clone_to_owned(&self) -> Self::Target { fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
Handshake { Handshake {
pstr: self.pstr.clone_to_owned(), pstr: self.pstr.clone_to_owned(within_buffer),
reserved: self.reserved, reserved: self.reserved,
info_hash: self.info_hash, info_hash: self.info_hash,
peer_id: self.peer_id, peer_id: self.peer_id,