use duplicate::duplicate_item;
#[cfg(feature = "async")]
use futures::{AsyncSeekExt, AsyncWrite};
use std::io::{Cursor, Result, Seek, Write};
use crate::{header::HEADER_BYTES, Compression, Directory, Entry};
const MAX_ROOT_DIR_LENGTH: u16 = 16384 - HEADER_BYTES as u16;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum WriteDirsOverflowStrategy {
OnlyLeafPointers {
start_size: Option<usize>,
},
}
impl Default for WriteDirsOverflowStrategy {
fn default() -> Self {
Self::OnlyLeafPointers { start_size: None }
}
}
#[duplicate_item(
fn_name async cfg_async_filter SeekFrom input_traits add_await(code) write_directory(directory, output, compression) only_leaf_pointer_strategy;
[write_directories_impl] [] [cfg(all())] [std::io::SeekFrom] [(impl Write + Seek)] [code] [directory.to_writer(output, compression)] [only_leaf_pointer_strategy];
[write_directories_impl_async] [async] [cfg(feature="async")] [futures::io::SeekFrom] [(impl AsyncWrite + Unpin + Send + AsyncSeekExt)] [code.await] [directory.to_async_writer(output, compression).await] [only_leaf_pointer_strategy_async];
)]
#[cfg_async_filter]
async fn fn_name(
output: &mut input_traits,
all_entries: &[Entry],
compression: Compression,
overflow_strategy: Option<WriteDirsOverflowStrategy>,
) -> Result<Vec<u8>> {
let start_pos = add_await([output.stream_position()])?;
{
let root_directory = Directory::from(all_entries.to_vec());
write_directory([root_directory], [output], [compression])?;
}
let root_directory_length = add_await([output.stream_position()])? - start_pos;
if root_directory_length <= u64::from(MAX_ROOT_DIR_LENGTH) {
return Ok(Vec::new());
}
match overflow_strategy.unwrap_or_default() {
WriteDirsOverflowStrategy::OnlyLeafPointers { start_size } => {
add_await([only_leaf_pointer_strategy(
output,
SeekFrom::Start(start_pos),
all_entries,
compression,
start_size,
)])
}
}
}
pub fn write_directories(
output: &mut (impl Write + Seek),
all_entries: &[Entry],
compression: Compression,
overflow_strategy: Option<WriteDirsOverflowStrategy>,
) -> Result<Vec<u8>> {
write_directories_impl(output, all_entries, compression, overflow_strategy)
}
#[allow(clippy::module_name_repetitions)]
#[cfg(feature = "async")]
pub async fn write_directories_async(
output: &mut (impl AsyncWrite + Unpin + Send + AsyncSeekExt),
all_entries: &[Entry],
compression: Compression,
overflow_strategy: Option<WriteDirsOverflowStrategy>,
) -> Result<Vec<u8>> {
write_directories_impl_async(output, all_entries, compression, overflow_strategy).await
}
#[duplicate_item(
fn_name cfg_async_filter async SeekFrom input_traits add_await(code) write_directory(directory, output, compression);
[only_leaf_pointer_strategy] [cfg(all())] [] [std::io::SeekFrom] [(impl Write + Seek)] [code] [directory.to_writer(output, compression)];
[only_leaf_pointer_strategy_async] [cfg(feature="async")] [async] [futures::io::SeekFrom] [(impl AsyncWrite + Unpin + Send + AsyncSeekExt)] [code.await] [directory.to_async_writer(output, compression).await];
)]
#[cfg_async_filter]
async fn fn_name(
output: &mut input_traits,
root_dir_start: SeekFrom,
all_entries: &[Entry],
compression: Compression,
start_size: Option<usize>,
) -> Result<Vec<u8>> {
let mut leaf_size = start_size.unwrap_or(4096);
loop {
let mut root_entries = Vec::<Entry>::new();
let mut leaf_dir_bytes = Vec::<u8>::new();
let mut leaf_dir_writer = Cursor::new(&mut leaf_dir_bytes);
for entries in all_entries.chunks(leaf_size) {
if entries.is_empty() {
continue;
}
let leaf_dir = Directory::from(entries.to_vec());
let offset = leaf_dir_writer.stream_position()?;
leaf_dir.to_writer(&mut leaf_dir_writer, compression)?;
#[allow(clippy::cast_possible_truncation)]
let length = (leaf_dir_writer.stream_position()? - offset) as u32;
root_entries.push(Entry {
tile_id: entries[0].tile_id,
length,
offset,
run_length: 0,
});
}
let root_directory = Directory::from(root_entries);
let start_pos = add_await([output.seek(root_dir_start)])?;
write_directory([root_directory], [output], [compression])?;
let root_directory_length = add_await([output.stream_position()])? - start_pos;
if root_directory_length <= u64::from(MAX_ROOT_DIR_LENGTH) {
return Ok(leaf_dir_bytes);
}
leaf_size *= 2;
}
}