sst 0.24.0

SST provides a sorted string table abstraction.
Documentation
//! Truncate a log file that has the final-partial-frame corruption case present.

use arrrg::CommandLine;
use arrrg_derive::CommandLine;

use sst::LogOptions;

#[derive(CommandLine, Debug, Default, Eq, PartialEq)]
struct LogTruncateFinalPartialFrameOptions {
    #[arrrg(flag, "Perform the truncation (default: log the offset).")]
    truncate: bool,
    #[arrrg(optional, "Truncate to this length (requires: --truncate).")]
    truncate_to: Option<u64>,
    #[arrrg(nested)]
    log: LogOptions,
}

fn main() {
    let (cmdline, args) = LogTruncateFinalPartialFrameOptions::from_command_line(
        "Usage: log-truncate-final-partial-frame [OPTIONS] <SST>",
    );
    if args.len() != 1 {
        eprintln!("specify exactly one sst");
        std::process::exit(1);
    }
    if let Some(offset) =
        sst::log::truncate_final_partial_frame(cmdline.log.clone(), &args[0]).unwrap()
    {
        if cmdline.truncate {
            if let Some(truncate_to) = cmdline.truncate_to {
                if offset != truncate_to || offset > i32::MAX as u64 {
                    eprintln!(
                        "not truncating: required offset={offset}, specified offset={truncate_to}"
                    );
                    std::process::exit(2);
                } else {
                    let path = std::ffi::CString::new(args[0].as_bytes()).unwrap();
                    // SAFETY(rescrv):  path is NUL-terminated and try_into has check above.
                    if unsafe { libc::truncate(path.as_ptr(), offset.try_into().unwrap()) } < 0 {
                        let err = std::io::Error::last_os_error();
                        eprintln!("truncate failed: {err:?}");
                        std::process::exit(3);
                    }
                }
            } else {
                eprintln!("not truncating: specify --truncate-to {offset} to truncate");
                std::process::exit(2);
            }
        } else {
            println!("truncate to {offset} bytes");
        }
    } else {
        println!("truncate cannot help");
    }
}