Skip to main content

fjall_cli/types/
byte_encoding.rs

1use errgonomic::{handle, handle_bool};
2use std::fs;
3use std::io;
4use std::path::PathBuf;
5use thiserror::Error;
6
7#[derive(clap::ValueEnum, Copy, Clone, Debug, Default, strum::Display)]
8#[clap(rename_all = "kebab")]
9#[strum(serialize_all = "kebab-case")]
10pub enum ByteEncoding {
11    Empty,
12    #[default]
13    String,
14    Hex,
15    Path,
16}
17
18impl ByteEncoding {
19    pub fn decode(&self, input: &str) -> Result<Vec<u8>, ByteEncodingDecodeError> {
20        use ByteEncoding::*;
21        use ByteEncodingDecodeError::*;
22        match self {
23            Empty => {
24                handle_bool!(input != "-", EmptyEncodingInvalid, input: input.to_owned());
25                Ok(Vec::new())
26            }
27            String => Ok(input.as_bytes().to_vec()),
28            Hex => Self::decode_hex(input),
29            Path => Self::decode_path(input),
30        }
31    }
32
33    pub fn decode_hex(input: &str) -> Result<Vec<u8>, ByteEncodingDecodeError> {
34        use ByteEncodingDecodeError::*;
35        let input = input.to_owned();
36        let bytes = handle!(hex::decode(&input), HexDecodeFailed, input);
37        Ok(bytes)
38    }
39
40    pub fn decode_path(input: &str) -> Result<Vec<u8>, ByteEncodingDecodeError> {
41        use ByteEncodingDecodeError::*;
42        let path = PathBuf::from(input);
43        let metadata = handle!(fs::metadata(&path), MetadataFailed, path);
44        handle_bool!(metadata.is_dir(), PathIsDirectory, path);
45        let bytes = handle!(fs::read(&path), ReadFailed, path);
46        Ok(bytes)
47    }
48}
49
50#[derive(Error, Debug)]
51pub enum ByteEncodingDecodeError {
52    #[error("empty encoding expects '-' but got '{input}'")]
53    EmptyEncodingInvalid { input: String },
54
55    #[error("failed to decode hex input '{input}'")]
56    HexDecodeFailed { source: hex::FromHexError, input: String },
57
58    #[error("failed to read metadata for path '{path}'")]
59    MetadataFailed { source: io::Error, path: PathBuf },
60
61    #[error("path '{path}' is a directory")]
62    PathIsDirectory { path: PathBuf },
63
64    #[error("failed to read bytes from path '{path}'")]
65    ReadFailed { source: io::Error, path: PathBuf },
66}