1use anyhow::{Context, Result};
10use clap::{Parser, ValueEnum};
11use common_traits::UnsignedInt;
12use log::info;
13use std::{
14 mem::size_of,
15 path::{Path, PathBuf},
16};
17
18use crate::GlobalArgs;
19
20#[derive(Parser, Debug)]
21#[command(name = "pad", about = "Zero-pad graph files to a length multiple of a word size.", long_about = None)]
22pub struct CliArgs {
23 pub file: PathBuf,
25 #[clap(value_enum)]
27 pub word_size: WordSize,
28}
29
30#[derive(ValueEnum, Clone, Debug, Default)]
31pub enum WordSize {
32 U16,
34 U32,
36 #[default]
38 U64,
39 U128,
41}
42
43pub fn main(_global_args: GlobalArgs, args: CliArgs) -> Result<()> {
44 let word_size = match args.word_size {
45 WordSize::U16 => size_of::<u16>(),
46 WordSize::U32 => size_of::<u32>(),
47 WordSize::U64 => size_of::<u64>(),
48 WordSize::U128 => size_of::<u128>(),
49 };
50
51 pad(args.file, word_size)
52}
53
54pub fn pad(path: impl AsRef<Path>, block_size: usize) -> Result<()> {
55 let path = path.as_ref();
56 let file_len = path
57 .metadata()
58 .with_context(|| format!("Cannot extract metadata from file {}", path.display()))?
59 .len();
60
61 let padded_len = file_len.align_to(block_size as u64);
62
63 if file_len == padded_len {
64 info!(
65 "The length of file {} is already a multiple of {}",
66 path.display(),
67 block_size
68 );
69 return Ok(());
70 }
71
72 let file = std::fs::File::options()
73 .read(true)
74 .write(true)
75 .open(path)
76 .with_context(|| format!("Cannot open file {} to pad", path.display()))?;
77 file.set_len(padded_len)
78 .with_context(|| format!("Cannot pad file {}", path.display()))?;
79 info!(
80 "File {} successfully zero-padded to a length multiple of {}",
81 path.display(),
82 block_size
83 );
84
85 Ok(())
86}