Compare commits

..

78 Commits

Author SHA1 Message Date
Christoph J. Scherr 2cbc6b3b25 chore: move everything to github for ci/cd
Rust CI / cargo CI (push) Has been cancelled Details
Release-plz / Release-plz release (push) Has been cancelled Details
Release-plz / Release-plz PR (push) Has been cancelled Details
2024-10-16 21:39:47 +02:00
Christoph J. Scherr c09a1f243a docs: more readme examples
cargo devel CI / cargo CI (push) Successful in 1m35s Details
2024-09-06 13:57:44 +02:00
Christoph J. Scherr 335a5b2013
chore: bump version
cargo devel CI / cargo CI (push) Successful in 1m35s Details
2024-09-06 13:46:10 +02:00
Christoph J. Scherr 6b79c023bb
docs: improve api docs for all of format.rs
cargo devel CI / cargo CI (push) Has been cancelled Details
2024-09-06 13:45:57 +02:00
Christoph J. Scherr fe71372de5
docs: document the parser functions
cargo devel CI / cargo CI (push) Successful in 1m40s Details
2024-09-06 13:13:53 +02:00
Christoph J. Scherr 0261d74acd
refactor: use logger for errors
cargo devel CI / cargo CI (push) Successful in 1m34s Details
2024-09-06 12:53:30 +02:00
Christoph J. Scherr df32a863d6
reafactor(numf_parser): add numf_parser_str and make numf_parser work with any data
cargo devel CI / cargo CI (push) Successful in 1m38s Details
2024-09-06 12:47:26 +02:00
Christoph J. Scherr 45409c4ff3
test: add tests for raw mode 2024-09-06 12:46:54 +02:00
Christoph J. Scherr 24ad56c111
feat: allow raw input with stdin
cargo devel CI / cargo CI (push) Successful in 1m39s Details
2024-09-06 12:17:51 +02:00
Christoph J. Scherr c18d1c09e9
docs: add raw mode to readme
cargo devel CI / cargo CI (push) Successful in 1m37s Details
2024-09-06 12:03:53 +02:00
cscherrNT f3d7d807d5 automatic cargo CI changes
cargo devel CI / cargo CI (push) Successful in 1m41s Details
2024-09-06 10:00:39 +00:00
Christoph J. Scherr c33b4ad1ed
Merge branch 'devel' of https://git.cscherr.de/PlexSheep/numf into devel
cargo devel CI / cargo CI (push) Successful in 1m54s Details
2024-09-06 11:58:50 +02:00
Christoph J. Scherr d315e24034
feat: output raw binary #26 2024-09-06 11:58:44 +02:00
cscherrNT 887a29d86a automatic cargo CI changes 2024-09-06 09:47:42 +00:00
Christoph J. Scherr e210b688f8
Merge branch 'devel' of https://git.cscherr.de/PlexSheep/numf into devel
cargo devel CI / cargo CI (push) Successful in 1m48s Details
2024-09-06 11:45:59 +02:00
Christoph J. Scherr 727b84e56b
feat: add logger 2024-09-06 11:45:58 +02:00
cscherrNT d7372b93a3 automatic cargo CI changes 2024-09-06 09:41:03 +00:00
Christoph J. Scherr e92af8acfa
refactor: write in binary now
cargo devel CI / cargo CI (push) Successful in 1m32s Details
Refs: #26
2024-09-06 11:39:36 +02:00
Christoph J. Scherr 23c653e9c0 chore: bump to v0.4.0
cargo devel CI / cargo CI (push) Successful in 1m18s Details
2024-05-23 13:29:26 +02:00
Christoph J. Scherr 03a2243a3e docs(main): add a few explanatory comments to main
cargo devel CI / cargo CI (push) Has been cancelled Details
2024-05-23 13:29:03 +02:00
Christoph J. Scherr 71f1f2ba08 docs(main): remove module level doc comment in main.rs (not needed) 2024-05-23 13:26:15 +02:00
Christoph J. Scherr c5790f9d79 Merge pull request 'output a random number' (#21) from feat/rand into devel
cargo devel CI / cargo CI (push) Successful in 1m24s Details
Reviewed-on: #21
2024-05-23 13:25:16 +02:00
PlexSheep 93a27564c6 automatic cargo CI changes 2024-05-22 22:21:49 +00:00
Christoph J. Scherr 3926be8aac Merge branch 'feat/rand' of https://git.cscherr.de/PlexSheep/numf into feat/rand
cargo devel CI / cargo CI (push) Successful in 1m29s Details
2024-05-23 00:20:15 +02:00
Christoph J. Scherr 8fbc612f5a feat(rand): #19 #21 add max rand and use number parser 2024-05-23 00:20:07 +02:00
PlexSheep 950c26a35c automatic cargo CI changes 2024-05-22 22:00:38 +00:00
Christoph J. Scherr 0923bf5247 feat(rand): add rand option to FormatOptions
cargo devel CI / cargo CI (push) Successful in 1m33s Details
The user can now specify how many rand values to add to the list. The
Cli needed some minor changes.

Refs: #21 #19
2024-05-22 23:59:08 +02:00
Christoph J. Scherr 826c3c7893 refactor(scripts): don't decorate the changelog with branch info and so on
cargo devel CI / cargo CI (push) Successful in 1m21s Details
2024-05-16 18:24:45 +02:00
Christoph J. Scherr 2da1887379 chore: bump to v0.3.3
cargo devel CI / cargo CI (push) Successful in 1m19s Details
2024-05-16 18:22:29 +02:00
Christoph J. Scherr d87d5d02da docs(readme): add install instructions for cargo with crates.io
cargo devel CI / cargo CI (push) Successful in 1m21s Details
2024-05-16 18:17:07 +02:00
Christoph J. Scherr 9c8446c78d docs(format): add module documentation and example
cargo devel CI / cargo CI (push) Successful in 1m17s Details
2024-05-16 18:10:05 +02:00
Christoph J. Scherr 3603c51ea9 docs(readme): fix typo
cargo devel CI / cargo CI (push) Successful in 1m17s Details
2024-05-16 17:57:26 +02:00
Christoph J. Scherr 947636cf0a chore: bump to v0.3.2
cargo devel CI / cargo CI (push) Successful in 1m16s Details
2024-05-16 17:53:41 +02:00
Christoph J. Scherr ccd4f7ac93 Merge pull request 'v0.3.2' (#18) from devel into master
cargo devel CI / cargo CI (push) Has been cancelled Details
Reviewed-on: #18
2024-05-16 17:52:46 +02:00
Christoph J. Scherr eba7d2fe01 docs(readme): change docs.rs link to the documentation instead of the crate
cargo devel CI / cargo CI (push) Successful in 1m18s Details
2024-05-16 17:50:19 +02:00
Christoph J. Scherr 1a87391d5e docs(readme): add fancy badges and mirror links
cargo devel CI / cargo CI (push) Successful in 1m17s Details
Refs: #6
2024-05-16 17:46:42 +02:00
Christoph J. Scherr f4b8927a6a docs(help): change formulation for numbers
cargo devel CI / cargo CI (push) Successful in 1m20s Details
2024-05-16 17:32:45 +02:00
Christoph J. Scherr 0520032ab5 docs: add some info to the readme
cargo devel CI / cargo CI (push) Successful in 1m16s Details
2024-05-13 17:14:47 +02:00
Christoph J. Scherr 9c9b476b22 docs: fix --help formatting
cargo devel CI / cargo CI (push) Has been cancelled Details
2024-05-13 17:13:33 +02:00
Christoph J. Scherr 83250589fb chore: remove unused dep clap-num and disable default features for libpt
cargo devel CI / cargo CI (push) Successful in 1m16s Details
2024-05-13 17:07:22 +02:00
Christoph J. Scherr b73850a25d chore: bump version to v0.3.1
cargo devel CI / cargo CI (push) Successful in 1m14s Details
2024-05-13 17:02:36 +02:00
Christoph J. Scherr bf4e7b00d7 fix: only read from stdin if it's not a terminal #17
cargo devel CI / cargo CI (push) Successful in 1m14s Details
2024-05-13 17:01:38 +02:00
Christoph J. Scherr f93e5f6c4c fix: parse first then add numbers from stdin #16
cargo devel CI / cargo CI (push) Successful in 1m15s Details
2024-05-13 16:55:39 +02:00
Christoph J. Scherr 09a7fa22cf Merge pull request 'v0.3.0' (#14) from devel into master
cargo devel CI / cargo CI (push) Successful in 1m15s Details
Reviewed-on: #14
2024-05-13 16:34:21 +02:00
Christoph J. Scherr 378e3d7fd2 chore: bump to v0.3.0
cargo devel CI / cargo CI (push) Successful in 1m17s Details
2024-05-13 16:34:08 +02:00
Christoph J. Scherr 706c06ce6f Merge pull request 'read numbers from stdin' (#15) from feat/numbers-from-stdin into devel
cargo devel CI / cargo CI (push) Successful in 1m13s Details
Reviewed-on: #15
2024-05-13 16:32:37 +02:00
Christoph J. Scherr 585bb41a9d refactor: split at whitespace #1 #15
cargo devel CI / cargo CI (push) Successful in 1m15s Details
2024-05-13 16:29:24 +02:00
Christoph J. Scherr 00c6b35ef3 feat: allow reading numbers from stdin #1
cargo devel CI / cargo CI (push) Successful in 1m16s Details
2024-05-13 16:26:35 +02:00
Christoph J. Scherr 1f4818ff98 Merge branch 'master' into devel
cargo devel CI / cargo CI (push) Successful in 1m15s Details
2024-05-13 15:55:04 +02:00
Christoph J. Scherr abb8ed4f2e Merge pull request 'add parser for all formats' (#13) from feat/parse-formats into devel
cargo devel CI / cargo CI (push) Has been cancelled Details
Reviewed-on: #13
2024-05-13 15:54:23 +02:00
PlexSheep 6f50918f27 automatic cargo CI changes 2024-05-13 13:53:39 +00:00
Christoph J. Scherr 7eb00e0f56 refactor: use libpt for joining the base64 parser vec #5 #13
cargo devel CI / cargo CI (push) Successful in 1m24s Details
2024-05-13 15:52:18 +02:00
Christoph J. Scherr 1bb0ffd6f8 refactor: use libpt to join the fast32 vecs into the integer type #13 #5
cargo devel CI / cargo CI (push) Successful in 1m19s Details
2024-05-13 15:45:38 +02:00
Christoph J. Scherr 2f14d672f4 chore: bump libpt to v0.5.1
cargo devel CI / cargo CI (push) Successful in 1m17s Details
2024-05-13 15:27:23 +02:00
Christoph J. Scherr 68d9cdaf69 feat: add hacky parsing for base32 and base64 #13 #5
cargo devel CI / cargo CI (push) Successful in 1m17s Details
2024-05-13 14:25:04 +02:00
Christoph J. Scherr 44be69a262 test: add prefix to base32 parser test #13 2024-05-13 14:24:40 +02:00
Christoph J. Scherr 47894a3f26 test: numf_parser test for all types that should be supported by the generic #13
cargo devel CI / cargo CI (push) Failing after 1m9s Details
2024-05-13 13:51:46 +02:00
Christoph J. Scherr 6649470ff7 refactor: numf_parser takes a generic unsigned int #13
cargo devel CI / cargo CI (push) Has been cancelled Details
2024-05-13 13:51:17 +02:00
Christoph J. Scherr c6ad45fb82 test: add tests for numf_parser #13
cargo devel CI / cargo CI (push) Failing after 1m17s Details
2024-05-13 13:39:56 +02:00
Christoph J. Scherr 18cccddbb2 test: fix numf_parser doctest #13 #5
cargo devel CI / cargo CI (push) Successful in 1m15s Details
2024-05-13 13:31:33 +02:00
Christoph J. Scherr 399021ecc6 feat: add a parser that can be used with clap for all formats except base32 and base64
cargo devel CI / cargo CI (push) Failing after 1m16s Details
Refs: #5
2024-05-13 13:19:49 +02:00
Christoph J. Scherr b007a54b4b docs: add base64 and base32 to the readme
cargo devel CI / cargo CI (push) Successful in 1m15s Details
2024-05-12 21:32:46 +02:00
Christoph J. Scherr 97608840b9 chore: bump version to v0.2.0
cargo devel CI / cargo CI (push) Successful in 1m16s Details
2024-05-12 21:21:34 +02:00
PlexSheep acdec5836e automatic cargo CI changes
cargo devel CI / cargo CI (push) Has been cancelled Details
2024-05-12 18:31:15 +00:00
Christoph J. Scherr 9700ae5b35 test: check set_format #12
cargo devel CI / cargo CI (push) Successful in 1m22s Details
2024-05-12 20:29:40 +02:00
Christoph J. Scherr 290b959b7e refactor: more derives
cargo devel CI / cargo CI (push) Has been cancelled Details
2024-05-12 20:29:12 +02:00
Christoph J. Scherr a88a03eab7 test: padded prefixed formatting #12
cargo devel CI / cargo CI (push) Successful in 1m12s Details
2024-05-12 20:25:48 +02:00
Christoph J. Scherr 1f91710bda chore: format tests
cargo devel CI / cargo CI (push) Successful in 1m14s Details
2024-05-12 20:23:47 +02:00
Christoph J. Scherr b681a6b04d Merge branch 'test/basics' of https://git.cscherr.de/PlexSheep/numf into test/basics 2024-05-12 20:23:05 +02:00
Christoph J. Scherr fe01412467 test: add prefix test #12 2024-05-12 20:23:04 +02:00
PlexSheep cd7f7cc376 automatic cargo CI changes 2024-05-12 18:21:54 +00:00
Christoph J. Scherr 9bfc8504a4 test: add padding test #12
cargo devel CI / cargo CI (push) Successful in 1m21s Details
2024-05-12 20:20:36 +02:00
Christoph J. Scherr 47ae8e135b feat: add setters for FormatOptions
cargo devel CI / cargo CI (push) Has been cancelled Details
2024-05-12 20:19:57 +02:00
Christoph J. Scherr 8b419048ef test: testing the format #12
cargo devel CI / cargo CI (push) Successful in 1m22s Details
2024-05-12 20:11:05 +02:00
Christoph J. Scherr 6251546a31 Merge pull request 'feat: padding and FormatOptions #9' (#11) from feat/padding into master
cargo devel CI / cargo CI (push) Successful in 1m14s Details
Reviewed-on: #11
2024-05-12 19:59:19 +02:00
Christoph J. Scherr 4f269fb509 refactor: add more derives
cargo devel CI / cargo CI (push) Successful in 1m11s Details
2024-05-12 19:54:45 +02:00
Christoph J. Scherr cae701815e refactor: use the cli struct as format options #11 #9
cargo devel CI / cargo CI (push) Has been cancelled Details
2024-05-12 19:53:38 +02:00
Christoph J. Scherr 82c1bf8d8a feat: padding and FormatOptions #9
cargo devel CI / cargo CI (push) Successful in 1m14s Details
2024-05-12 19:34:01 +02:00
11 changed files with 1088 additions and 159 deletions

View File

@ -1,46 +0,0 @@
name: cargo devel CI
on:
push:
branches:
- '**'
# - '!master'
jobs:
format:
name: cargo CI
permissions:
# Give the default GITHUB_TOKEN write permission to commit and push the
# added or changed files to the repository.
contents: write
steps:
- name: get repo
uses: actions/checkout@v4
- name: install rust
uses: https://github.com/dtolnay/rust-toolchain@stable
- name: install additional rust things
run: |
rustup component add rustfmt
rustup component add clippy
- name: config custom registry
run: |
mkdir -p ~/.cargo/
echo "" > ~/.cargo/config.toml
echo "[registry]" >> ~/.cargo/config.toml
echo 'cscherr = "cscherr"' >> ~/.cargo/config.toml
echo '[registries.cscherr]' >> ~/.cargo/config.toml
echo 'index = "https://git.cscherr.de/PlexSheep/_cargo-index.git"' >> ~/.cargo/config.toml
cat ~/.cargo/config.toml
- name: cargo clippy check
run: cargo clippy --all-features --all-targets --workspace
- name: cargo clippy fix
run: cargo clippy --fix --all-features --all-targets --workspace
- name: cargo fmt
run: cargo fmt --all
- name: cargo test
run: cargo test --all-features --all-targets --workspace && cargo test --all-features --workspace --doc
- name: commit back to repository
uses: https://github.com/stefanzweifel/git-auto-commit-action@v5
with:
# Optional. Commit message for the created commit.
# Defaults to "Apply automatic changes"
commit_message: automatic cargo CI changes

7
.github/dependabot.yaml vendored Normal file
View File

@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
# Check for updates every Monday
schedule:
interval: "weekly"

View File

@ -1,10 +1,16 @@
name: cargo devel CI
name: Rust CI
on:
pull_request:
branches:
- '**'
push:
branches:
- '**'
# - '!master'
env:
CARGO_TERM_COLOR: always
jobs:
CI:
runs-on: ubuntu-latest
@ -38,10 +44,10 @@ jobs:
- name: cargo fmt
run: cargo fmt --all
- name: cargo test
run: cargo test --all-features --all-targets --workspace && cargo test --all-features --workspace --doc
run: cargo test --all-features --all-targets --workspace
- name: commit back to repository
uses: stefanzweifel/git-auto-commit-action@v5
with:
# Optional. Commit message for the created commit.
# Defaults to "Apply automatic changes"
commit_message: automatic cargo CI changes
commit_message: "ci: automatic Rust CI changes"

54
.github/workflows/release.yaml vendored Normal file
View File

@ -0,0 +1,54 @@
name: Release-plz
permissions:
pull-requests: write
contents: write
on:
push:
branches:
- master
- main
jobs:
# Release unpublished packages.
release-plz-release:
name: Release-plz release
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run release-plz
uses: MarcoIeni/release-plz-action@v0.5
with:
command: release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
# Create a PR with the new versions and changelog, preparing the next release.
release-plz-pr:
name: Release-plz PR
runs-on: ubuntu-latest
concurrency:
group: release-plz-${{ github.ref }}
cancel-in-progress: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run release-plz
uses: MarcoIeni/release-plz-action@v0.5
with:
command: release-pr
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

View File

@ -1,6 +1,6 @@
[package]
name = "numf"
version = "0.1.0"
version = "0.4.1"
edition = "2021"
publish = true
authors = ["Christoph J. Scherr <software@cscherr.de>"]
@ -16,7 +16,7 @@ categories = ["command-line-utilities", "encoding"]
[dependencies]
anyhow = "1.0.83"
clap = { version = "4.5.4", features = ["derive"] }
clap-num = "1.1.1"
fast32 = "1.0.2"
libpt = { version = "0.5.0", features = ["bintols"]}
libpt = { version = "0.6.0", features = ["bintols", "log", "cli"] }
num = "0.4.3"
rand = "0.8.5"

View File

@ -1,5 +1,15 @@
# numf
![Project badge](https://img.shields.io/badge/language-Rust-blue.svg)
![Crates.io License](https://img.shields.io/crates/l/numf)
![GitHub Release](https://img.shields.io/github/v/release/PlexSheep/numf)
![GitHub language count](https://img.shields.io/github/languages/count/PlexSheep/numf)
[![Rust CI](https://github.com/PlexSheep/numf/actions/workflows/cargo.yaml/badge.svg)](https://github.com/PlexSheep/numf/actions/workflows/cargo.yaml)
* [GitHub](https://github.com/PlexSheep/numf)
* [crates.io](https://crates.io/crates/numf)
* [docs.rs](https://docs.rs/numf/latest/numf/)
`numf` is a number formatter. It formats the numbers provided to it.
Current formats are:
@ -8,9 +18,13 @@ Current formats are:
- Binary
- Octal
- Decimal
- Base32
- Base64
- Raw
`numf` also has the option of prepending a prefix for each format, such as
`0x` for hexadecimal.
`numf` also has the option of prepending a prefix for the formats, such as
`0x` for hexadecimal. Numbers may also be provided from the stdin. See `--help`
flag for more information.
## Example
@ -19,4 +33,34 @@ $ numf -xp 1337 505 0xaabb
0x539
0x1F9
0xAABB
$ numf -a 505 | hedxump -C
00000000 01 f9 |..|
00000002
$ numf -a 505 | numf
1F9
$ numf -a 505 | numf -d
505
$ numf -a 505 | numf -b
111111001
$ echo -ne "\x20\xff\xb4" | numf -xpP
0x20FFB4
$ echo -ne "\x20\xff\xb4" | numf -d
2162612
$ base64='aGVsbG8gd29ybGQuCg==' ; echo "0s$base64" | numf -d
8271117963529473544792763018762
$ base64='aGVsbG8gd29ybGQuCg==' ; echo "0s$base64" | numf -s
aGVsbG8gd29ybGQuCg==
$ echo "0b100100101010" | numf -d
2346
$ echo "0b100100101010" | numf -bPp
0b0000100100101010
```
## Installing
### Cargo
`numf` is on [crates.io](https://crates.io).
```
cargo install numf
```

View File

@ -4,7 +4,7 @@ NEW_VERSION=$(cat Cargo.toml | rg '^\s*version\s*=\s*"([^"]*)"\s*$' -or '$1')
GIT_COMMIT_SHA=$(git rev-parse HEAD)
REPO=${PWD##*/} # name of cwd
BODY="
$(git log $(git describe --tags --abbrev=0)..HEAD --pretty="- %s" --oneline --decorate)
$(git log $(git describe --tags --abbrev=0)..HEAD --pretty="- %s" --oneline --no-decorate)
"
USER=PlexSheep
git tag "v$NEW_VERSION" || echo "could not tag"

View File

@ -1,57 +1,637 @@
use libpt::bintols::split;
//! This module implements the actual formatting in [numf](crate).
//!
//! You can use it in your own program to convert numbers to formats.
//!
//! # Example
//!
//! The following example shows how to use numf to format your integers.
//!
//! ```
//! use numf::format::{Format, FormatOptions};
//!
//! let mut options = FormatOptions::default();
//! options.set_prefix(true);
//! options.set_padding(true);
//!
//! assert_eq!(Format::Hex.format_str(0x1337, &options), "0x1337");
//! assert_eq!(Format::Base32.format_str(0x41414242, &options), "032sIFAUEQQ=");
//! assert_eq!(Format::Base64.format_str(0x41414242, &options), "0sQUFCQg==");
//! // sometimes you might need the raw bytes instead of a String
//! assert_eq!(Format::Raw.format(0x1337, &options), vec![0x00, 0x13, 0x37]);
//! assert_eq!(Format::Hex.format(0x1337, &options), vec![48, 120, 49, 51, 51, 55]);
//!
//! options.set_prefix(false);
//! options.set_padding(false);
//!
//! assert_eq!(Format::Hex.format_str(0x1337, &options), "1337");
//! assert_eq!(Format::Base32.format_str(0x41414242, &options), "IFAUEQQ=");
//! assert_eq!(Format::Base64.format_str(0x41414242, &options), "QUFCQg==");
//!
//! assert_eq!(Format::Raw.format(0x1337, &options), vec![0x13, 0x37]);
//! assert_eq!(Format::Hex.format(0x1337, &options), vec![49, 51, 51, 55]);
//! ```
pub type Num = u128;
#![allow(dead_code)]
use std::fmt::Display;
#[derive(Copy, Clone, Debug)]
// this is exported to lib.rs
use anyhow::anyhow;
use clap::{ArgGroup, Parser};
use libpt::bintols::{join, split};
use libpt::cli::args::VerbosityLevel;
use libpt::log::{debug, trace};
/// The number type [numf](crate) uses
pub type NumberType = u128;
/// Describes a format for numbers
///
/// [Format] can be used to convert unsigned integers into a textual or other representation. See
/// [Format::format_str] for more. It is also possible to parse the various represenations to
/// a rust integer, see [numf_parser_str] for that.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Default)]
pub enum Format {
Dec,
#[default]
Hex,
Bin,
Octal,
Base64,
Base32,
/// Write raw data, not text
Raw,
}
impl Display for Format {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
/// Describes what the formatter should do exactly
///
/// Use [Self::default] to get a basic variant or create a object yourself.
///
/// This struct can be parsed with [clap] derive.
///
/// # Example
///
/// ```
/// use numf::format::{Format, FormatOptions};
/// let mut options = FormatOptions::default();
///
/// assert_eq!(Format::Bin.format_str(256, &options), "100000000");
/// assert_eq!(Format::Hex.format_str(256, &options), "100");
/// assert_eq!(Format::Base64.format_str(256, &options), "AQA=");
///
/// options.set_prefix(true);
/// options.set_padding(true);
///
/// assert_eq!(Format::Bin.format_str(256, &options), "0b0000000100000000");
/// assert_eq!(Format::Hex.format_str(256, &options), "0x0100");
/// assert_eq!(Format::Base64.format_str(256, &options), "0sAQA=");
///
/// ```
#[derive(Parser, Debug, Clone, PartialEq, Eq, Hash)]
#[clap(author, version, about, long_about = None)]
#[command(
author,
version,
about,
long_about,
help_template = r#"{about-section}
{usage-heading} {usage}
{all-args}{tab}
{name}: {version}
Author: {author-with-newline}
"#
)]
#[clap(group(
ArgGroup::new("format")
.args(&["hex", "bin", "oct", "dec", "base64", "base32", "raw"]),
))]
pub struct FormatOptions {
#[arg(short, long)]
/// add a prefix (like "0x" for hex)
prefix: bool,
#[arg(short = 'P', long)]
/// add a padding to make the number at least one byte long
///
/// For example, `0b1100` will be `0b00001100` with this.
/// This does not apply to all formats, only hexadecimal and binary.
padding: bool,
#[arg(short = 'x', long)]
/// format to hexadecimal
hex: bool,
#[arg(short, long)]
/// format to binary
bin: bool,
#[arg(short, long)]
/// format to decimal
dec: bool,
#[arg(short, long)]
/// format to octal
oct: bool,
#[arg(short = 's', long)]
/// format to base64
base64: bool,
#[arg(short = 'a', long)]
/// format raw, no text
raw: bool,
#[arg(short = 'r', long, default_value_t = 0, value_parser=numf_parser_str::<NumberType>)]
/// output random numbers
///
/// Add a user defined amount of cryptographically pseudorandom numbers to the number list.
rand: NumberType,
#[arg(long, default_value_t = NumberType::MAX, value_parser=numf_parser_str::<NumberType>)]
/// max for the random numbers
///
/// Generated numbers will not be lower than this. Only has an effect with --rand set.
rand_max: NumberType,
#[arg(short = 'z', long)]
/// format to base32
base32: bool,
#[clap(value_parser=numf_parser_str::<NumberType>, required=false)]
/// numbers that should be formatted
///
/// Any of the [Formats](Format::format) are supported, but the prefixes are needed for formats
/// other than decimal.
///
/// Formats:
///
/// * '0x' - Hexadecimal
///
/// * '0b' - Binary
///
/// * '0o' - Octal
///
/// * '0s' - Base64
///
/// * '032s' - Base32
///
/// The numbers may be left empty at first, if numbers are provided from the stdin.
numbers: Vec<NumberType>,
#[command(flatten)]
pub(crate) verbosity: VerbosityLevel,
}
impl FormatOptions {
/// get the format that the user has configured
pub fn format(&self) -> Format {
trace!("self.hex: {}", self.hex);
if self.oct {
Format::Octal
} else if self.bin {
Format::Bin
} else if self.dec {
Format::Dec
} else if self.base64 {
Format::Base64
} else if self.base32 {
Format::Base32
} else if self.hex {
Format::Hex
} else if self.raw {
Format::Raw
} else {
// none was explicitly selected
debug!("no mode was explicitly selected, going with the default");
Format::default()
}
}
/// set the format manually
pub fn set_format(&mut self, format: Format) {
self.bin = false;
self.oct = false;
self.dec = false;
self.hex = false;
self.base64 = false;
self.raw = false;
self.base32 = false;
match format {
Format::Bin => self.bin = true,
Format::Raw => self.raw = true,
Format::Hex => self.hex = true,
Format::Octal => self.oct = true,
Format::Base64 => self.base64 = true,
Format::Base32 => self.base32 = true,
Format::Dec => self.dec = true,
}
}
/// get numbers
pub fn numbers(&self) -> &[u128] {
self.numbers.as_ref()
}
/// set numbers manually
pub fn set_numbers(&mut self, numbers: Vec<NumberType>) {
self.numbers = numbers;
}
/// set padding manually
pub fn set_padding(&mut self, value: bool) {
self.padding = value
}
/// get padding
pub fn padding(&self) -> bool {
self.padding
}
/// get prefix
pub fn prefix(&self) -> bool {
self.prefix
}
/// set prefix manually
pub fn set_prefix(&mut self, value: bool) {
self.prefix = value;
}
/// manually add a number
pub fn push_number(&mut self, value: NumberType) {
self.numbers.push(value)
}
/// get rand
pub fn rand(&self) -> NumberType {
self.rand
}
/// set amount of extra random numbers manually
pub fn set_rand(&mut self, rand: NumberType) {
self.rand = rand;
}
/// get highes allowed random value
pub fn rand_max(&self) -> NumberType {
self.rand_max
}
/// set highes allowed random value
pub fn set_rand_max(&mut self, rand_max: NumberType) {
self.rand_max = rand_max;
}
}
impl Default for FormatOptions {
fn default() -> Self {
Self {
padding: false,
prefix: false,
oct: false,
hex: false,
bin: false,
raw: false,
base32: false,
base64: false,
dec: false,
numbers: vec![],
rand: 0,
rand_max: NumberType::MAX,
verbosity: VerbosityLevel::default(),
}
}
}
impl Format {
pub fn prefix(&self) -> String {
/// Get the perfix for that [Format] as [Vec<u8>].
///
/// # Example
///
/// ```
/// # use numf::format::Format;
/// assert_eq!(Format::Bin.prefix_str(), "0b");
/// assert_eq!(Format::Dec.prefix_str(), "0d");
/// assert_eq!(Format::Hex.prefix_str(), "0x");
/// assert_eq!(Format::Octal.prefix_str(), "0o");
/// assert_eq!(Format::Base64.prefix_str(), "0s");
/// assert_eq!(Format::Base32.prefix_str(), "032s");
/// assert_eq!(Format::Raw.prefix_str(), "\x00");
/// ```
pub fn prefix_str(&self) -> String {
String::from_utf8_lossy(&self.prefix()).to_string()
}
/// Get the perfix for that [Format] as [Vec<u8>].
///
/// # Example
///
/// ```
/// # use numf::format::Format;
/// assert_eq!(Format::Bin.prefix(), b"0b");
/// assert_eq!(Format::Dec.prefix(), b"0d");
/// assert_eq!(Format::Hex.prefix(), b"0x");
/// assert_eq!(Format::Octal.prefix(), b"0o");
/// assert_eq!(Format::Base64.prefix(), b"0s");
/// assert_eq!(Format::Base32.prefix(), b"032s");
/// assert_eq!(Format::Raw.prefix(), vec![0x00]);
/// ```
pub fn prefix(&self) -> Vec<u8> {
match self {
// apperently used nowhere, sometimes 0 is used as a prefix but I
// think this makes it more clear that this is decimal
Format::Dec => "0d",
Format::Dec => b"0d".to_vec(),
Format::Raw => [0x00].to_vec(),
// very common
Format::Hex => "0x",
Format::Hex => b"0x".to_vec(),
// very common
Format::Bin => "0b",
Format::Bin => b"0b".to_vec(),
// somewhat common
Format::Octal => "0o",
Format::Octal => b"0o".to_vec(),
// perl and a few other programs seem to use this too
Format::Base64 => "0s",
Format::Base64 => b"0s".to_vec(),
// no idea, I made this up
Format::Base32 => "032s",
Format::Base32 => b"032s".to_vec(),
}
.to_string()
}
pub fn format(&self, num: Num, prefix: bool) -> String {
let mut buf = String::new();
if prefix {
buf += &self.prefix();
/// format a number with a [Format] and [FormatOptions] to a [String]
///
/// If you need raw byte outputs, use [Format::format] instead.
///
/// # Example
///
/// ```
/// use numf::format::{Format, FormatOptions};
/// let mut options = FormatOptions::default();
///
/// assert_eq!(Format::Bin.format_str(256, &options), "100000000");
/// assert_eq!(Format::Hex.format_str(256, &options), "100");
/// assert_eq!(Format::Base64.format_str(256, &options), "AQA=");
///
/// options.set_prefix(true);
/// options.set_padding(true);
///
/// assert_eq!(Format::Bin.format_str(256, &options), "0b0000000100000000");
/// assert_eq!(Format::Hex.format_str(256, &options), "0x0100");
/// assert_eq!(Format::Base64.format_str(256, &options), "0sAQA=");
///
/// ```
pub fn format_str(&self, num: NumberType, options: &FormatOptions) -> String {
String::from_utf8_lossy(&self.format(num, options)).to_string()
}
/// format a number with a [Format] and [FormatOptions] to a byte vector [Vec<u8>]
///
/// If you need [String] outputs, use [Format::format_str] instead.
///
/// # Example
///
/// ```
/// use numf::format::{Format, FormatOptions};
/// let mut options = FormatOptions::default();
///
/// assert_eq!(Format::Bin.format(256, &options), b"100000000");
/// assert_eq!(Format::Hex.format(256, &options), b"100");
/// assert_eq!(Format::Hex.format(256, &options), [49, 48, 48]);
/// assert_eq!(Format::Base64.format(256, &options), b"AQA=");
/// assert_eq!(Format::Raw.format(256, &options), [1, 0]);
///
/// options.set_prefix(true);
/// options.set_padding(true);
///
/// assert_eq!(Format::Bin.format(256, &options), b"0b0000000100000000");
/// assert_eq!(Format::Hex.format(256, &options), b"0x0100");
/// assert_eq!(Format::Hex.format(256, &options), [48, 120, 48, 49, 48, 48]);
/// assert_eq!(Format::Base64.format(256, &options), b"0sAQA=");
/// assert_eq!(Format::Raw.format(256, &options), [0, 1, 0]);
/// assert_eq!(Format::Raw.format(255, &options), [0, 255]);
/// assert_eq!(Format::Raw.format(32000, &options), [0, 125, 0]);
///
/// ```
pub fn format(&self, num: NumberType, options: &FormatOptions) -> Vec<u8> {
debug!("formatting mode: {self}");
let mut buf: Vec<u8> = Vec::new();
if options.prefix() {
buf.append(&mut self.prefix());
debug!("prefix the buffer: {buf:X?}");
}
match self {
Format::Hex => {
buf += &format!("{num:X}");
if options.padding() {
let tmp = &format!("{num:X}");
let tmp1 = &("0".repeat((2 - tmp.len() % 2) % 2) + tmp);
buf.append(&mut tmp1.as_bytes().to_owned());
} else {
buf.append(&mut format!("{num:X}").as_bytes().to_owned());
}
}
Format::Bin => {
buf += &format!("{num:b}");
if options.padding() {
let tmp = &format!("{num:b}");
let tmp1 = &("0".repeat((8 - tmp.len() % 8) % 8) + tmp);
buf.append(&mut tmp1.as_bytes().to_owned());
} else {
buf.append(&mut format!("{num:b}").as_bytes().to_owned());
}
Format::Octal => {
buf += &format!("{num:o}");
}
Format::Dec => {
buf += &format!("{num}");
}
Format::Base64 => buf += &fast32::base64::RFC4648.encode(&split::unsigned_to_vec(num)),
Format::Base32 => buf += &fast32::base32::RFC4648.encode(&split::unsigned_to_vec(num)),
Format::Octal => buf.append(&mut format!("{num:o}").as_bytes().to_owned()),
Format::Dec => buf.append(&mut format!("{num}").as_bytes().to_owned()),
Format::Base64 => buf.append(
&mut fast32::base64::RFC4648
.encode(&split::unsigned_to_vec(num))
.as_bytes()
.to_owned(),
),
Format::Base32 => buf.append(
&mut fast32::base32::RFC4648
.encode(&split::unsigned_to_vec(num))
.as_bytes()
.to_owned(),
),
// Format::Raw => buf.append(&mut split::unsigned_to_vec(num)),
Format::Raw => buf.append(&mut split::unsigned_to_vec(num)),
}
buf
}
}
/// Converts a &[str] into an unsigned integer value (like [u128]), according to one of the [Formats](Format)
///
/// The number is assumed to be base-10 by default, it is parsed as a different
/// [Format] if the number is prefixed with the [prefix](FormatOptions::prefix),
/// for that [Format]. So if the user inputs `0b1100` then this is parsed as
/// [Binary](Format::Bin) and so on.
///
/// If you also want to parse raw inputs, use [numf_parser].
///
/// # Returns
///
/// This parser will only output unsigned integers, it cannot be used with signed integers.
///
/// # Example
///
/// This allows base-10 addresses to be passed normally, or values formatted with any of the
/// [Formats](format::Format) defined by this crate to be passed when prefixed with the respective
/// prefix.
///
/// ```
/// use clap::Parser;
/// use numf::format::numf_parser_str;
///
/// #[derive(Parser)]
/// struct Args {
/// #[clap(short, long, value_parser=numf_parser_str::<u128>)]
/// address: u128,
/// }
/// let args = Args::parse_from(&["", "-a", "0x10"]);
/// assert_eq!(args.address, 16);
/// ```
pub fn numf_parser_str<T>(s: &str) -> anyhow::Result<T>
where
T: std::str::FromStr + std::convert::TryFrom<u128>,
<T as std::str::FromStr>::Err: std::fmt::Display,
T: num::Num,
<T as num::Num>::FromStrRadixErr: std::fmt::Display,
<T as std::str::FromStr>::Err: std::fmt::Debug,
u128: std::convert::From<T>,
<T as std::str::FromStr>::Err: std::error::Error,
<T as std::convert::TryFrom<u128>>::Error: std::error::Error,
<T as std::convert::TryFrom<u128>>::Error: std::marker::Send,
<T as std::convert::TryFrom<u128>>::Error: std::marker::Sync,
<T as std::convert::TryFrom<u128>>::Error: 'static,
{
numf_parser(s.as_bytes())
}
/// Converts any data (as bytes) into an unsigned integer value `T` (like [u128]), according to one of the [Formats](Format)
///
/// If you only want to parse text data, use [numf_parser_str] instead.
///
/// The parser will first try to convert the data to a [String].
///
/// Then, the number is assumed to be base-10 by default, it is parsed as a different
/// [Format] if the number is prefixed with the [prefix](FormatOptions::prefix),
/// for that [Format]. So if the user inputs `0b1100` then this is parsed as
/// [Binary](Format::Bin) and so on.
///
/// If none of the text [Formats](Format) matches, the data will be assumed to be raw and converted
/// to the ingeger type directly.
///
/// # Errors
///
/// If no text [Format] matches and the data is too long for the integer `T`.
///
/// # Returns
///
/// This parser will only output unsigned integers, it cannot be used with signed integers.
///
/// # Example
///
/// ```
/// use numf::format::numf_parser;
///
/// let data = &[0x15, 0x92, 0xff];
/// let result: u64 = 0x1592ff;
/// assert_eq!(result, numf_parser(data).unwrap());
///
/// let data = b"0x1337";
/// let result: u64 = 0x1337;
/// assert_eq!(result, numf_parser(data).unwrap());
///
/// let data = b"0b110011";
/// let result: u64 = 0b110011;
/// assert_eq!(result, numf_parser(data).unwrap());
/// ```
pub fn numf_parser<T>(data: &[u8]) -> anyhow::Result<T>
where
T: std::str::FromStr + std::convert::TryFrom<u128>,
<T as std::str::FromStr>::Err: std::fmt::Display,
T: num::Num,
<T as num::Num>::FromStrRadixErr: std::fmt::Display,
<T as std::str::FromStr>::Err: std::fmt::Debug,
u128: std::convert::From<T>,
<T as std::str::FromStr>::Err: std::error::Error,
<T as std::convert::TryFrom<u128>>::Error: std::error::Error,
<T as std::convert::TryFrom<u128>>::Error: std::marker::Send,
<T as std::convert::TryFrom<u128>>::Error: std::marker::Sync,
<T as std::convert::TryFrom<u128>>::Error: 'static,
{
let data_as_text = String::from_utf8_lossy(data).to_string();
if data_as_text.starts_with(&Format::Dec.prefix_str()) || data_as_text.parse::<T>().is_ok() {
let s = match data_as_text.strip_prefix(&Format::Dec.prefix_str()) {
Some(sr) => sr,
None => &data_as_text,
};
match s.parse() {
Ok(r) => Ok(r),
Err(e) => {
let e = format!("{e}");
Err(anyhow!(e))
}
}
} else if data_as_text.starts_with(&Format::Hex.prefix_str()) {
let s = match data_as_text.strip_prefix(&Format::Hex.prefix_str()) {
Some(sr) => sr,
None => &data_as_text,
};
match T::from_str_radix(s, 16) {
Ok(r) => Ok(r),
Err(e) => {
let e = format!("{e}");
Err(anyhow!(e))
}
}
} else if data_as_text.starts_with(&Format::Octal.prefix_str()) {
let s = match data_as_text.strip_prefix(&Format::Octal.prefix_str()) {
Some(sr) => sr,
None => &data_as_text,
};
match T::from_str_radix(s, 8) {
Ok(r) => Ok(r),
Err(e) => {
let e = format!("{e}");
Err(anyhow!(e))
}
}
} else if data_as_text.starts_with(&Format::Bin.prefix_str()) {
let s = match data_as_text.strip_prefix(&Format::Bin.prefix_str()) {
Some(sr) => sr,
None => &data_as_text,
};
match T::from_str_radix(s, 2) {
Ok(r) => Ok(r),
Err(e) => {
let e = format!("{e}");
Err(anyhow!(e))
}
}
} else if data_as_text.starts_with(&Format::Base64.prefix_str()) {
let s = match data_as_text.strip_prefix(&Format::Base64.prefix_str()) {
Some(sr) => sr,
None => &data_as_text,
};
match fast32::base64::RFC4648.decode_str(s) {
Ok(r) => Ok(join::array_to_unsigned::<T>(&r)?),
Err(e) => {
let e = format!("{e}");
Err(anyhow!(e))
}
}
} else if data_as_text.starts_with(&Format::Base32.prefix_str()) {
let s = match data_as_text.strip_prefix(&Format::Base32.prefix_str()) {
Some(sr) => sr,
None => &data_as_text,
};
match fast32::base32::RFC4648.decode_str(s) {
Ok(r) => Ok(join::array_to_unsigned::<T>(&r)?),
Err(e) => {
let e = format!("{e}");
Err(anyhow!(e))
}
}
} else {
// what could go wrong with interpreting everything else as raw number input
let s: Vec<u8> = if data.len() > 2 && data[0] == 0x00 {
data.iter().skip(1).map(ToOwned::to_owned).collect()
} else {
data.as_ref().to_vec()
};
Ok(join::array_to_unsigned(&s)?)
}
}

View File

@ -1,10 +1,17 @@
//! Format numbers
//!
//! This crate contains several utility functions for formatting numbers
//! into other systems, such as converting decimal numbers to hexadecimal.
//! into other systems, such as converting decimal numbers to hexadecimal
//! , and back.
//!
//! See [Format] for supported formats.
//! See [format::Format] for supported formats.
//!
//! Note that this crate is primarily used as a executable.
//! Note that this crate is primarily intended to be used as a executable.
//!
//! Highlights:
//! * [format::numf_parser]
//! * [format::numf_parser_str]
//! * [format::Format::format]
//! * [format::Format::format_str]
pub mod format;

View File

@ -1,91 +1,96 @@
//! # numf
//!
//! This binary should just take any amount of numbers and print them out formatted to some other
//! system.
use std::io::{IsTerminal, Read, Write};
use std::process::exit;
use clap::{ArgGroup, Parser};
use clap_num::maybe_hex;
use clap::{CommandFactory, Parser};
use numf::format::numf_parser_str;
mod format;
use crate::format::{numf_parser, Format};
use format::*;
use libpt::log::{debug, error};
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
#[command(
author,
version,
about,
long_about,
help_template = r#"{about-section}
{usage-heading} {usage}
{all-args}{tab}
fn main() -> anyhow::Result<()> {
// try to read from stdin first, appending the numbers we read to the FormatOptions
let mut options = FormatOptions::parse();
let _logger = libpt::log::Logger::builder()
.set_level(options.verbosity.level())
.display_time(false)
.build()
.map_err(|e| {
error!("could not initialize logger: {e}");
});
debug!("logger active");
{name}: {version}
Author: {author-with-newline}
"#
)]
#[clap(group(
ArgGroup::new("format")
.args(&["hex", "bin", "oct", "dec", "base64", "base32"]),
))]
struct Cli {
#[arg(short, long)]
/// add a prefix (like "0x" for hex)
prefix: bool,
#[arg(short = 'x', long, default_value_t = true)]
/// format to hexadecimal
hex: bool,
#[arg(short, long)]
/// format to binary
bin: bool,
#[arg(short, long)]
/// format to decimal
dec: bool,
#[arg(short, long)]
/// format to octal
oct: bool,
#[arg(short = 's', long)]
/// format to base64
base64: bool,
#[arg(short = 'z', long)]
/// format to base32
base32: bool,
#[clap(value_parser=maybe_hex::<Num>, required=true)]
/// at least one number that should be formatted
///
/// supports either base 10 or base 16 inputs (with 0xaaaa)
numbers: Vec<Num>,
}
impl Cli {
fn format(&self) -> Format {
if self.oct {
Format::Octal
} else if self.bin {
Format::Bin
} else if self.dec {
Format::Dec
} else if self.base64 {
Format::Base64
} else if self.base32 {
Format::Base32
} else if self.hex {
Format::Hex
} else {
unreachable!()
let mut stdin_nums = Vec::new();
let stdin = std::io::stdin();
// only accept numbers from stdin if the stdin is not an interactive terminal
if !stdin.is_terminal() {
match stdin.lock().read_to_end(&mut stdin_nums) {
Ok(_) => {
let whole: String = match String::from_utf8(stdin_nums.clone()) {
Ok(r) => r,
Err(_) => {
let number = match numf_parser(&stdin_nums) {
Ok(n) => n,
Err(e) => {
eprintln!("{}", FormatOptions::command().render_usage());
error!("could raw inputs from stdin as numbers: {e:#?}");
exit(2);
}
};
options.push_number(number);
String::new()
}
};
let split = whole.split_whitespace();
for s in split {
let number = match numf_parser_str(s) {
Ok(n) => n,
Err(e) => {
eprintln!("{}", FormatOptions::command().render_usage());
error!("could not parse number from stdin: {e:#?}");
exit(2);
}
};
options.push_number(number)
}
}
}
Err(e) => {
eprintln!("{}", FormatOptions::command().render_usage());
error!("could not read from stdin: {e:#?}");
exit(2);
}
};
}
fn main() {
let cli = Cli::parse();
// add random numbers to the number list, according to how many are requested
if options.rand() > 0 {
use rand::prelude::*;
let mut rand = rand::rngs::OsRng;
for _i in 0..options.rand() {
options.push_number(rand.gen_range(0..options.rand_max()));
}
}
let mut out: Vec<String> = Vec::new();
// exit with error if no numbers are to be formatted
if options.numbers().is_empty() {
eprintln!("{}", FormatOptions::command().render_usage());
error!("no numbers have been provided");
exit(1);
}
for num in &cli.numbers {
out.push(cli.format().format(*num, cli.prefix));
let mut out: Vec<Vec<u8>> = Vec::new();
for num in options.numbers() {
out.push(options.format().format(*num, &options));
}
for o in out {
println!("{o}")
let mut stdout = std::io::stdout();
stdout.write_all(&o)?;
if options.format() != Format::Raw {
stdout.write_all(b"\n")?;
}
stdout.flush()?;
}
Ok(())
}

272
tests/format.rs Normal file
View File

@ -0,0 +1,272 @@
use numf::format::*;
#[test]
fn format() {
let options = FormatOptions::default();
assert_eq!(Format::Dec.format_str(1337, &options), "1337");
assert_eq!(
Format::Dec.format_str(u128::MAX, &options),
format!("{}", u128::MAX)
);
assert_eq!(Format::Hex.format_str(0x1337, &options), "1337");
assert_eq!(
Format::Hex.format_str(u128::MAX, &options),
format!("{:X}", u128::MAX)
);
assert_eq!(
Format::Bin.format_str(0b1010001001010010010100111, &options),
"1010001001010010010100111"
);
assert_eq!(
Format::Bin.format_str(u128::MAX, &options),
format!("{:b}", u128::MAX)
);
assert_eq!(Format::Octal.format_str(0o13377331, &options), "13377331");
assert_eq!(
Format::Octal.format_str(u128::MAX, &options),
format!("{:o}", u128::MAX)
);
assert_eq!(Format::Base32.format_str(0x41414242, &options), "IFAUEQQ=");
assert_eq!(
Format::Base32.format_str(0x4141414141414141, &options),
"IFAUCQKBIFAUC==="
);
assert_eq!(Format::Base64.format_str(0x41414242, &options), "QUFCQg==");
assert_eq!(
Format::Base64.format_str(0x4141414141414141, &options),
"QUFBQUFBQUE="
);
assert_eq!(Format::Raw.format(0x1337, &options), vec![0x13, 0x37]);
assert_eq!(Format::Raw.format(0x0, &options), vec![0x0]);
}
#[test]
fn format_padding() {
let mut options = FormatOptions::default();
options.set_padding(true);
assert_eq!(Format::Dec.format_str(1337, &options), "1337");
assert_eq!(
Format::Dec.format_str(u128::MAX, &options),
format!("{}", u128::MAX)
);
assert_eq!(Format::Hex.format_str(0xFFF, &options), "0FFF");
assert_eq!(Format::Hex.format_str(0xFFFF, &options), "FFFF");
assert_eq!(
Format::Hex.format_str(u128::MAX, &options),
format!("{:X}", u128::MAX)
);
assert_eq!(
Format::Bin.format_str(0b11110000_00001111, &options),
"1111000000001111"
);
assert_eq!(
Format::Bin.format_str(0b110000_00001111, &options),
"0011000000001111"
);
assert_eq!(
Format::Bin.format_str(u128::MAX, &options),
format!("{:b}", u128::MAX)
);
assert_eq!(Format::Octal.format_str(0o13377331, &options), "13377331");
assert_eq!(
Format::Octal.format_str(u128::MAX, &options),
format!("{:o}", u128::MAX)
);
assert_eq!(Format::Base32.format_str(0x41414242, &options), "IFAUEQQ=");
assert_eq!(
Format::Base32.format_str(0x4141414141414141, &options),
"IFAUCQKBIFAUC==="
);
assert_eq!(Format::Base64.format_str(0x41414242, &options), "QUFCQg==");
assert_eq!(
Format::Base64.format_str(0x4141414141414141, &options),
"QUFBQUFBQUE="
);
assert_eq!(Format::Raw.format(0x1337, &options), vec![0x13, 0x37]);
assert_eq!(Format::Raw.format(0x0, &options), vec![0x0]);
}
#[test]
fn format_prefix() {
let mut options = FormatOptions::default();
options.set_prefix(true);
assert_eq!(Format::Dec.format_str(1337, &options), "0d1337");
assert_eq!(
Format::Dec.format_str(u128::MAX, &options),
format!("0d{}", u128::MAX)
);
assert_eq!(Format::Hex.format_str(0x1337, &options), "0x1337");
assert_eq!(
Format::Hex.format_str(u128::MAX, &options),
format!("0x{:X}", u128::MAX)
);
assert_eq!(
Format::Bin.format_str(0b1010001001010010010100111, &options),
"0b1010001001010010010100111"
);
assert_eq!(
Format::Bin.format_str(u128::MAX, &options),
format!("0b{:b}", u128::MAX)
);
assert_eq!(Format::Octal.format_str(0o13377331, &options), "0o13377331");
assert_eq!(
Format::Octal.format_str(u128::MAX, &options),
format!("0o{:o}", u128::MAX)
);
assert_eq!(
Format::Base32.format_str(0x41414242, &options),
"032sIFAUEQQ="
);
assert_eq!(
Format::Base32.format_str(0x4141414141414141, &options),
"032sIFAUCQKBIFAUC==="
);
assert_eq!(
Format::Base64.format_str(0x41414242, &options),
"0sQUFCQg=="
);
assert_eq!(
Format::Base64.format_str(0x4141414141414141, &options),
"0sQUFBQUFBQUE="
);
assert_eq!(Format::Raw.format(0x1337, &options), vec![0x0, 0x13, 0x37]);
assert_eq!(Format::Raw.format(0x0, &options), vec![0x0, 0x0]);
}
#[test]
fn format_padded_prefix() {
let mut options = FormatOptions::default();
options.set_prefix(true);
options.set_padding(true);
assert_eq!(Format::Dec.format_str(1337, &options), "0d1337");
assert_eq!(
Format::Dec.format_str(u128::MAX, &options),
format!("0d{}", u128::MAX)
);
assert_eq!(Format::Hex.format_str(0xFFF, &options), "0x0FFF");
assert_eq!(Format::Hex.format_str(0xFFFF, &options), "0xFFFF");
assert_eq!(
Format::Hex.format_str(u128::MAX, &options),
format!("0x{:X}", u128::MAX)
);
assert_eq!(
Format::Bin.format_str(0b11110000_00001111, &options),
"0b1111000000001111"
);
assert_eq!(
Format::Bin.format_str(0b110000_00001111, &options),
"0b0011000000001111"
);
assert_eq!(
Format::Bin.format_str(u128::MAX, &options),
format!("0b{:b}", u128::MAX)
);
assert_eq!(Format::Octal.format_str(0o13377331, &options), "0o13377331");
assert_eq!(
Format::Octal.format_str(u128::MAX, &options),
format!("0o{:o}", u128::MAX)
);
assert_eq!(
Format::Base32.format_str(0x41414242, &options),
"032sIFAUEQQ="
);
assert_eq!(
Format::Base32.format_str(0x4141414141414141, &options),
"032sIFAUCQKBIFAUC==="
);
assert_eq!(
Format::Base64.format_str(0x41414242, &options),
"0sQUFCQg=="
);
assert_eq!(
Format::Base64.format_str(0x4141414141414141, &options),
"0sQUFBQUFBQUE="
);
assert_eq!(Format::Raw.format(0x1337, &options), vec![0x0, 0x13, 0x37]);
assert_eq!(Format::Raw.format(0x0, &options), vec![0x0, 0x0]);
}
#[test]
fn set_format_checker() {
let mut options = FormatOptions::default();
assert_eq!(options.format(), Format::Hex);
options.set_format(Format::Base32);
assert_eq!(options.format(), Format::Base32);
options.set_format(Format::Base64);
assert_eq!(options.format(), Format::Base64);
options.set_format(Format::Raw);
assert_eq!(options.format(), Format::Raw);
}
#[test]
fn parser_dec() {
assert_eq!(numf_parser_str::<u32>("1337").unwrap(), 1337);
assert_eq!(numf_parser_str::<u32>("0d1337").unwrap(), 1337);
}
#[test]
fn parser_bin() {
assert_eq!(numf_parser_str::<u32>("0b11001").unwrap(), 0b11001);
assert_eq!(numf_parser_str::<u32>("0b11001").unwrap(), 0b11001);
}
#[test]
fn parser_hex() {
assert_eq!(numf_parser_str::<u32>("0xdeadbeef").unwrap(), 0xdeadbeef);
}
#[test]
fn parser_oct() {
assert_eq!(numf_parser_str::<u32>("0o771171").unwrap(), 0o771171);
}
#[test]
fn parser_b64() {
assert_eq!(numf_parser_str::<u32>("0sQUFCQg==").unwrap(), 0x41414242);
}
#[test]
fn parser_b32() {
assert_eq!(numf_parser_str::<u32>("032sIFAUEQQ=").unwrap(), 0x41414242);
}
#[test]
fn parser_raw() {
assert_eq!(numf_parser_str::<u32>("\x00\x50\x60").unwrap(), 0x5060);
}
#[test]
fn parser_generics() {
assert_eq!(numf_parser_str::<u8>("55").unwrap(), 55);
assert_eq!(numf_parser_str::<u16>("55").unwrap(), 55);
assert_eq!(numf_parser_str::<u32>("55").unwrap(), 55);
assert_eq!(numf_parser_str::<u64>("55").unwrap(), 55);
assert_eq!(numf_parser_str::<u128>("55").unwrap(), 55);
}