Skip to content

Commit

Permalink
Select piece length when none is provided
Browse files Browse the repository at this point in the history
When no piece length is provided to imdl torrent create, a piece
length is selected based on the size of the input. The hueristic is
lifted directly from libtorrent.

Also adds a imdl torrent piece-length command, which prints a table
of the piece lengths chosen at different content sizes, which is useful
for understanding and debugging the piece length selection algorithm.

type: added
  • Loading branch information
casey committed Apr 8, 2020
1 parent 35a0e8f commit 5a1de1a
Show file tree
Hide file tree
Showing 15 changed files with 325 additions and 72 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ features = ["default", "wrap_help"]
[workspace]
members = [
# generate table of contents and table of supported BEPs in README.md
"bin/update-readme"
"bin/update-readme",
]
60 changes: 55 additions & 5 deletions src/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,25 @@ const EI: u128 = PI << 10;
const ZI: u128 = EI << 10;
const YI: u128 = ZI << 10;

#[derive(Debug, PartialEq, Copy, Clone)]
#[derive(Debug, PartialEq, Copy, Clone, PartialOrd, Ord, Eq)]
pub(crate) struct Bytes(pub(crate) u128);

impl Bytes {
pub(crate) fn from(bytes: impl Into<u128>) -> Bytes {
Bytes(bytes.into())
}

pub(crate) fn is_power_of_two(self) -> bool {
self.0 == 0 || self.0 & (self.0 - 1) == 0
}

pub(crate) fn kib() -> Self {
Bytes::from(KI)
}

pub(crate) fn mib() -> Self {
Bytes::from(MI)
}

pub(crate) fn count(self) -> u128 {
self.0
}
}

fn float_to_int(x: f64) -> u128 {
Expand All @@ -36,6 +44,48 @@ fn int_to_float(x: u128) -> f64 {
x as f64
}

impl<I: Into<u128>> From<I> for Bytes {
fn from(n: I) -> Bytes {
Bytes(n.into())
}
}

impl Div<Bytes> for Bytes {
type Output = u128;

fn div(self, rhs: Bytes) -> u128 {
self.0 / rhs.0
}
}

impl Div<u128> for Bytes {
type Output = Bytes;

fn div(self, rhs: u128) -> Bytes {
Bytes::from(self.0 / rhs)
}
}

impl DivAssign<u128> for Bytes {
fn div_assign(&mut self, rhs: u128) {
self.0 /= rhs;
}
}

impl Mul<u128> for Bytes {
type Output = Bytes;

fn mul(self, rhs: u128) -> Self {
Bytes::from(self.0 * rhs)
}
}

impl MulAssign<u128> for Bytes {
fn mul_assign(&mut self, rhs: u128) {
self.0 *= rhs;
}
}

impl FromStr for Bytes {
type Err = Error;

Expand Down
11 changes: 6 additions & 5 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub(crate) use std::{
hash::Hash,
io::{self, Read, Write},
num::ParseFloatError,
ops::{Div, DivAssign, Mul, MulAssign},
path::{Path, PathBuf},
process::{self, Command, ExitStatus},
str::{self, FromStr},
Expand All @@ -35,7 +36,7 @@ pub(crate) use url::Url;
pub(crate) use walkdir::WalkDir;

// modules
pub(crate) use crate::{bencode, consts, error, torrent, use_color};
pub(crate) use crate::{bencode, consts, error, use_color};

// traits
pub(crate) use crate::{
Expand All @@ -45,10 +46,10 @@ pub(crate) use crate::{

// structs and enums
pub(crate) use crate::{
bytes::Bytes, env::Env, error::Error, file_info::FileInfo, hasher::Hasher, info::Info,
lint::Lint, metainfo::Metainfo, mode::Mode, opt::Opt, platform::Platform, style::Style,
subcommand::Subcommand, table::Table, torrent::Torrent, torrent_summary::TorrentSummary,
use_color::UseColor,
bytes::Bytes, env::Env, error::Error, file_info::FileInfo, files::Files, hasher::Hasher,
info::Info, lint::Lint, linter::Linter, metainfo::Metainfo, mode::Mode, opt::Opt,
piece_length_picker::PieceLengthPicker, platform::Platform, style::Style, table::Table,
torrent_summary::TorrentSummary, use_color::UseColor,
};

// test stdlib types
Expand Down
29 changes: 29 additions & 0 deletions src/files.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::common::*;

pub(crate) struct Files {
total_size: Bytes,
}

impl Files {
pub(crate) fn from_root(root: &Path) -> Result<Files, Error> {
let mut total_size = 0;

for result in WalkDir::new(root).sort_by(|a, b| a.file_name().cmp(b.file_name())) {
let entry = result?;

let metadata = entry.metadata()?;

if metadata.is_file() {
total_size += metadata.len();
}
}

Ok(Files {
total_size: Bytes::from(total_size),
})
}

pub(crate) fn total_size(&self) -> Bytes {
self.total_size
}
}
25 changes: 25 additions & 0 deletions src/linter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::common::*;

pub(crate) struct Linter {
allowed: BTreeSet<Lint>,
}

impl Linter {
pub(crate) fn new() -> Linter {
Linter {
allowed: BTreeSet::new(),
}
}

pub(crate) fn allow(&mut self, allowed: impl IntoIterator<Item = Lint>) {
self.allowed.extend(allowed)
}

pub(crate) fn is_allowed(&self, lint: Lint) -> bool {
self.allowed.contains(&lint)
}

pub(crate) fn is_denied(&self, lint: Lint) -> bool {
!self.is_allowed(lint)
}
}
9 changes: 7 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
clippy::result_unwrap_used,
clippy::shadow_reuse,
clippy::unreachable,
clippy::unseparated_literal_suffix,
clippy::wildcard_enum_match_arm
)]

Expand All @@ -36,6 +37,9 @@ mod errln;
#[macro_use]
mod err;

#[macro_use]
mod outln;

#[cfg(test)]
mod testing;

Expand All @@ -55,22 +59,23 @@ mod consts;
mod env;
mod error;
mod file_info;
mod files;
mod hasher;
mod info;
mod into_u64;
mod into_usize;
mod lint;
mod linter;
mod metainfo;
mod mode;
mod opt;
mod path_ext;
mod piece_length_picker;
mod platform;
mod platform_interface;
mod reckoner;
mod style;
mod subcommand;
mod table;
mod torrent;
mod torrent_summary;
mod use_color;

Expand Down
15 changes: 15 additions & 0 deletions src/opt.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
use crate::common::*;

mod torrent;

#[derive(StructOpt)]
pub(crate) enum Subcommand {
Torrent(torrent::Torrent),
}

impl Subcommand {
pub(crate) fn run(self, env: &mut Env, unstable: bool) -> Result<(), Error> {
match self {
Self::Torrent(torrent) => torrent.run(env, unstable),
}
}
}

#[derive(StructOpt)]
#[structopt(
about(consts::ABOUT),
Expand Down
12 changes: 8 additions & 4 deletions src/torrent.rs → src/opt/torrent.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::common::*;

mod create;
mod piece_length;
mod show;
mod stats;

Expand All @@ -11,17 +12,20 @@ mod stats;
about("Subcommands related to the BitTorrent protocol.")
)]
pub(crate) enum Torrent {
Create(torrent::create::Create),
Stats(torrent::stats::Stats),
Show(torrent::show::Show),
Create(create::Create),
#[structopt(alias = "piece-size")]
PieceLength(piece_length::PieceLength),
Show(show::Show),
Stats(stats::Stats),
}

impl Torrent {
pub(crate) fn run(self, env: &mut Env, unstable: bool) -> Result<(), Error> {
match self {
Self::Create(create) => create.run(env),
Self::Stats(stats) => stats.run(env, unstable),
Self::PieceLength(piece_length) => piece_length.run(env),
Self::Show(show) => show.run(env),
Self::Stats(stats) => stats.run(env, unstable),
}
}
}
Loading

0 comments on commit 5a1de1a

Please sign in to comment.