webgraph_cli/run/
pad.rs

1/*
2 * SPDX-FileCopyrightText: 2024 Matteo Dell'Acqua
3 * SPDX-FileCopyrightText: 2024 Sebastiano Vigna
4 * SPDX-FileCopyrightText: 2024 Tommaso Fontana
5 *
6 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
7 */
8
9use 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    /// The file to pad, usually it's either a graph or offsets.
24    pub file: PathBuf,
25    /// The word size to pad to.
26    #[clap(value_enum)]
27    pub word_size: WordSize,
28}
29
30#[derive(ValueEnum, Clone, Debug, Default)]
31pub enum WordSize {
32    /// 2 bytes
33    U16,
34    /// 4 bytes
35    U32,
36    /// 8 bytes
37    #[default]
38    U64,
39    /// 16 bytes
40    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}