use super::*;
use std::sync::Arc;
#[derive(Clone, Debug)]
pub struct OwnedMetainfo {
data: Arc<Data>,
}
#[derive(Debug)]
struct Data {
source: Arc<[u8]>,
index: Index,
limits: Limits,
}
#[derive(Debug)]
struct Index {
info: Range<usize>,
name: Range<usize>,
hashes: Range<usize>,
info_hash: InfoHashV1,
private: bool,
layout: Layout<'static>,
}
impl OwnedMetainfo {
pub fn parse(input: &[u8], limits: Limits) -> Result<Self, Error> {
let parsed = Metainfo::parse(input, limits)?;
let index = Index::new(input, parsed);
Ok(Self {
data: Arc::new(Data {
source: Arc::from(input),
index,
limits,
}),
})
}
pub fn view(&self) -> MetainfoView<'_> {
MetainfoView {
info_hash: self.info_hash(),
layout: self.layout(),
hashes: &self.data.source[self.data.index.hashes.clone()],
}
}
pub fn source_bytes(&self) -> &[u8] {
&self.data.source
}
pub fn info_bytes(&self) -> &[u8] {
&self.data.source[self.data.index.info.clone()]
}
pub fn info_hash(&self) -> InfoHashV1 {
self.data.index.info_hash
}
pub fn name(&self) -> &[u8] {
&self.data.source[self.data.index.name.clone()]
}
pub fn is_private(&self) -> bool {
self.data.index.private
}
pub fn layout(&self) -> &Layout<'static> {
&self.data.index.layout
}
pub fn piece_hash(&self, index: u32) -> Option<&[u8; 20]> {
hash_at(
&self.data.source[self.data.index.hashes.clone()],
index,
self.layout().piece_count(),
)
}
pub fn decode_document(&self) -> Node<'_> {
bencode::decode(&self.data.source, self.data.limits)
.expect("immutable validated metainfo document")
}
}
impl Index {
fn new(source: &[u8], parsed: Metainfo<'_>) -> Self {
let Metainfo {
info_bytes,
info_hash,
name,
private,
piece_hashes,
layout,
..
} = parsed;
Self {
info: span(source, info_bytes),
name: span(source, name),
hashes: span(source, piece_hashes),
info_hash,
private,
layout: Layout {
files: layout
.files
.into_iter()
.map(|file| File {
path: file
.path
.into_iter()
.map(|part| Cow::Owned(part.into_owned()))
.collect(),
offset: file.offset,
length: file.length,
kind: file.kind,
})
.collect(),
total_length: layout.total_length,
piece_length: layout.piece_length,
piece_count: layout.piece_count,
multi_file: layout.multi_file,
},
}
}
}
fn span(source: &[u8], part: &[u8]) -> Range<usize> {
let start = (part.as_ptr() as usize)
.checked_sub(source.as_ptr() as usize)
.expect("decoded metainfo subslice");
let end = start
.checked_add(part.len())
.filter(|&end| end <= source.len())
.expect("decoded metainfo span within source");
start..end
}