Compare commits
No commits in common. "main" and "547edb04bebd048a0833cc1056c5c078e7b4e5d6" have entirely different histories.
main
...
547edb04be
26 changed files with 2586 additions and 208 deletions
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "cargo" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
60
.github/workflows/mdbook.yml
vendored
Normal file
60
.github/workflows/mdbook.yml
vendored
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
# Sample workflow for building and deploying a mdBook site to GitHub Pages
|
||||||
|
#
|
||||||
|
# To get started with mdBook see: https://rust-lang.github.io/mdBook/index.html
|
||||||
|
#
|
||||||
|
name: Deploy mdBook site to Pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
# Runs on pushes targeting the default branch
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
||||||
|
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
||||||
|
concurrency:
|
||||||
|
group: "pages"
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Build job
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
MDBOOK_VERSION: 0.4.36
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install mdBook
|
||||||
|
run: |
|
||||||
|
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh
|
||||||
|
rustup update
|
||||||
|
cargo install --version ${MDBOOK_VERSION} mdbook
|
||||||
|
- name: Setup Pages
|
||||||
|
id: pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
- name: Build with mdBook
|
||||||
|
run: mdbook build
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ./book
|
||||||
|
|
||||||
|
# Deployment job
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
18
.github/workflows/publish.yml
vendored
Normal file
18
.github/workflows/publish.yml
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
name: Publish Crate
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
create-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
- uses: katyo/publish-crates@v2
|
||||||
|
with:
|
||||||
|
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
18
.github/workflows/release-please.yml
vendored
Normal file
18
.github/workflows/release-please.yml
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
name: Release Please
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release-please:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: google-github-actions/release-please-action@v4
|
||||||
|
with:
|
||||||
|
release-type: rust
|
55
.github/workflows/rust-clippy.yml
vendored
Normal file
55
.github/workflows/rust-clippy.yml
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# This workflow uses actions that are not certified by GitHub.
|
||||||
|
# They are provided by a third-party and are governed by
|
||||||
|
# separate terms of service, privacy policy, and support
|
||||||
|
# documentation.
|
||||||
|
# rust-clippy is a tool that runs a bunch of lints to catch common
|
||||||
|
# mistakes in your Rust code and help improve your Rust code.
|
||||||
|
# More details at https://github.com/rust-lang/rust-clippy
|
||||||
|
# and https://rust-lang.github.io/rust-clippy/
|
||||||
|
|
||||||
|
name: rust-clippy analyze
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ "main" ]
|
||||||
|
schedule:
|
||||||
|
- cron: '25 0 * * 5'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
rust-clippy-analyze:
|
||||||
|
name: Run rust-clippy analyzing
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af #@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: stable
|
||||||
|
components: clippy
|
||||||
|
override: true
|
||||||
|
|
||||||
|
- name: Install required cargo
|
||||||
|
run: cargo install clippy-sarif sarif-fmt
|
||||||
|
|
||||||
|
- name: Run rust-clippy
|
||||||
|
run:
|
||||||
|
cargo clippy
|
||||||
|
--all-features
|
||||||
|
--message-format=json | clippy-sarif | tee rust-clippy-results.sarif | sarif-fmt
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Upload analysis results to GitHub
|
||||||
|
uses: github/codeql-action/upload-sarif@v2
|
||||||
|
with:
|
||||||
|
sarif_file: rust-clippy-results.sarif
|
||||||
|
wait-for-processing: true
|
21
.github/workflows/rust.yml
vendored
Normal file
21
.github/workflows/rust.yml
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
name: Rust
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
pull_request:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Build
|
||||||
|
run: cargo build --verbose
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test --verbose
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
|
docs/book
|
||||||
/target
|
/target
|
||||||
|
|
3
.release-please-manifest.json
Normal file
3
.release-please-manifest.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
".": "0.0.0"
|
||||||
|
}
|
1808
Cargo.lock
generated
1808
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
18
Cargo.toml
18
Cargo.toml
|
@ -1,30 +1,40 @@
|
||||||
[package]
|
[package]
|
||||||
name = "okid"
|
name = "okid"
|
||||||
version = "0.1.3"
|
version = "0.1.39"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
publish = ["oksoftware"]
|
readme = "README.md"
|
||||||
|
description = "A library for gereating double clickable ids"
|
||||||
|
license = "BSD-3-Clause"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
async-graphql = { version = "7.0.11", optional = true }
|
||||||
blake3 = { version = "1.5.4", optional = true }
|
blake3 = { version = "1.5.4", optional = true }
|
||||||
|
bytes = { version = "1.7.2", features = ["serde"] }
|
||||||
digest = "0.10.7"
|
digest = "0.10.7"
|
||||||
enumflags2 = "0.7.10"
|
enumflags2 = "0.7.10"
|
||||||
|
git2 = { version = "0.18.3", optional = true, default-features = false }
|
||||||
hex = { version = "0.4.3", features = ["serde"] }
|
hex = { version = "0.4.3", features = ["serde"] }
|
||||||
|
jetstream_wireformat = "6.0.0"
|
||||||
serde = { version = "1.0.210", features = ["derive"] }
|
serde = { version = "1.0.210", features = ["derive"] }
|
||||||
serde_bytes = "0.11.15"
|
serde_json = "1.0.128"
|
||||||
sha1 = { version = "0.10.6", optional = true }
|
sha1 = { version = "0.10.6", optional = true }
|
||||||
sha2 = { version = "0.10.8", optional = true }
|
sha2 = { version = "0.10.8", optional = true }
|
||||||
sha3 = { version = "0.10.8", optional = true }
|
sha3 = { version = "0.10.8", optional = true }
|
||||||
ulid = { version = "1.1.3", optional = true, features = ["uuid"] }
|
ulid = { version = "1.1.3", optional = true, features = ["uuid"] }
|
||||||
|
utoipa = { version = "^5.0.0-beta.0", optional = true }
|
||||||
uuid = { version = "1.10.0", optional = true, features = ["js", "v4"] }
|
uuid = { version = "1.10.0", optional = true, features = ["js", "v4"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["sha1", "sha2", "sha3", "blake3", "uuid", "ulid"]
|
default = ["sha1", "sha2", "sha3", "blake3", "uuid", "ulid", "openapi"]
|
||||||
sha1 = ["dep:sha1"]
|
sha1 = ["dep:sha1"]
|
||||||
sha2 = ["dep:sha2"]
|
sha2 = ["dep:sha2"]
|
||||||
sha3 = ["dep:sha3"]
|
sha3 = ["dep:sha3"]
|
||||||
blake3 = ["dep:blake3"]
|
blake3 = ["dep:blake3"]
|
||||||
uuid = ["dep:uuid"]
|
uuid = ["dep:uuid"]
|
||||||
ulid = ["dep:ulid"]
|
ulid = ["dep:ulid"]
|
||||||
|
openapi = ["dep:utoipa"]
|
||||||
|
git = ["dep:git2"]
|
||||||
|
graphql = ["dep:async-graphql"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
insta = { version = "1.40.0", features = ["yaml"] }
|
insta = { version = "1.40.0", features = ["yaml"] }
|
||||||
|
|
23
README.md
23
README.md
|
@ -2,4 +2,25 @@
|
||||||
|
|
||||||
# okid
|
# okid
|
||||||
|
|
||||||
IDs represented as self identifying strings.
|
`okid` is a library for generating double clickable representations of various types of data,
|
||||||
|
such as `sha1` hashes, `uuid`s and more.
|
||||||
|
|
||||||
|
## sha1
|
||||||
|
```rust
|
||||||
|
use sha1::Digest as sha1digest;
|
||||||
|
let hasher = sha1::Sha1::new();
|
||||||
|
let binary_id = okid::OkId::from(hasher);
|
||||||
|
```
|
||||||
|
## sha256
|
||||||
|
```rust
|
||||||
|
use sha2::Digest;
|
||||||
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(b"hello world");
|
||||||
|
let binary_id = okid::OkId::from(hasher);
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting strings look like this:
|
||||||
|
`2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9`
|
||||||
|
first character of the string is the type of the binary data
|
||||||
|
in this case 2 means sha256
|
||||||
|
the rest of the string is the hexadecimal representation of the binary data
|
||||||
|
|
5
book.toml
Normal file
5
book.toml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[book]
|
||||||
|
authors = ["sevki"]
|
||||||
|
language = "en"
|
||||||
|
multilingual = false
|
||||||
|
src = "docs/src"
|
3
docs/src/SUMMARY.md
Normal file
3
docs/src/SUMMARY.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
- [Intro](intro.md)
|
26
docs/src/intro.md
Normal file
26
docs/src/intro.md
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<img src="https://assets.ok.software/okid.png" align="right" width="200">
|
||||||
|
|
||||||
|
# okid
|
||||||
|
|
||||||
|
`okid` is a library for generating double clickable representations of various types of data,
|
||||||
|
such as `sha1` hashes, `uuid`s and more.
|
||||||
|
|
||||||
|
## sha1
|
||||||
|
```rust
|
||||||
|
use sha1::Digest as sha1digest;
|
||||||
|
let hasher = sha1::Sha1::new();
|
||||||
|
let binary_id = okid::OkId::from(hasher);
|
||||||
|
```
|
||||||
|
## sha256
|
||||||
|
```rust
|
||||||
|
use sha2::Digest;
|
||||||
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(b"hello world");
|
||||||
|
let binary_id = okid::OkId::from(hasher);
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting strings look like this:
|
||||||
|
`2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9`
|
||||||
|
first character of the string is the type of the binary data
|
||||||
|
in this case 2 means sha256
|
||||||
|
the rest of the string is the hexadecimal representation of the binary data
|
BIN
docs/src/okRust.png
Normal file
BIN
docs/src/okRust.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 273 KiB |
Before Width: | Height: | Size: 438 KiB After Width: | Height: | Size: 438 KiB |
14
release-please-config.json
Normal file
14
release-please-config.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"packages": {
|
||||||
|
".": {
|
||||||
|
"package-name": "okrust",
|
||||||
|
"changelog-path": "CHANGELOG.md",
|
||||||
|
"release-type": "rust",
|
||||||
|
"bump-minor-pre-major": false,
|
||||||
|
"bump-patch-for-minor-pre-major": true,
|
||||||
|
"draft": false,
|
||||||
|
"prerelease": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use crate::{BinaryType, Digest, OkId};
|
use crate::{BinaryType, Digest, IntoOkId, OkId};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub(super) struct Blake3(pub(super) [u8; 32]);
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
||||||
pub(super) struct Blake3([u8; 32]);
|
|
||||||
impl From<blake3::Hasher> for OkId {
|
impl From<blake3::Hasher> for OkId {
|
||||||
fn from(value: blake3::Hasher) -> Self {
|
fn from(value: blake3::Hasher) -> Self {
|
||||||
let data = value.finalize();
|
let data = value.finalize();
|
||||||
|
@ -20,6 +21,8 @@ impl From<blake3::Hasher> for OkId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IntoOkId for blake3::Hasher {}
|
||||||
|
|
||||||
impl Display for Blake3 {
|
impl Display for Blake3 {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let data = self.0;
|
let data = self.0;
|
||||||
|
|
36
src/fingerprint.rs
Normal file
36
src/fingerprint.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
|
use super::{BinaryType, Digest, IntoOkId, OkId};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub(super) struct Fingerprint(pub(super) u64);
|
||||||
|
|
||||||
|
impl From<u64> for OkId {
|
||||||
|
fn from(value: u64) -> Self {
|
||||||
|
Self {
|
||||||
|
hash_type: BinaryType::Fingerprint,
|
||||||
|
digest: Digest::Fingerprint(Fingerprint(value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoOkId for u64 {}
|
||||||
|
|
||||||
|
impl Display for Fingerprint {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let buf = hex::encode(self.0.to_be_bytes());
|
||||||
|
f.write_str(&buf)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Fingerprint {
|
||||||
|
type Err = super::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let buf = hex::decode(s)?;
|
||||||
|
let mut hash: [u8; 8] = [0; 8];
|
||||||
|
hash.copy_from_slice(&buf);
|
||||||
|
Ok(Fingerprint(u64::from_be_bytes(hash)))
|
||||||
|
}
|
||||||
|
}
|
526
src/lib.rs
526
src/lib.rs
|
@ -8,7 +8,6 @@
|
||||||
//! use sha1::Digest as sha1digest;
|
//! use sha1::Digest as sha1digest;
|
||||||
//! let hasher = sha1::Sha1::new();
|
//! let hasher = sha1::Sha1::new();
|
||||||
//! let binary_id = okid::OkId::from(hasher);
|
//! let binary_id = okid::OkId::from(hasher);
|
||||||
//! insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709"###);
|
|
||||||
//! ```
|
//! ```
|
||||||
//! ## sha256
|
//! ## sha256
|
||||||
//! ```rust
|
//! ```rust
|
||||||
|
@ -16,13 +15,10 @@
|
||||||
//! let mut hasher = sha2::Sha256::new();
|
//! let mut hasher = sha2::Sha256::new();
|
||||||
//! hasher.update(b"hello world");
|
//! hasher.update(b"hello world");
|
||||||
//! let binary_id = okid::OkId::from(hasher);
|
//! let binary_id = okid::OkId::from(hasher);
|
||||||
//! insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
|
||||||
//! 2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
|
||||||
//! "###);
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! The resulting strings look like this:
|
//! The resulting strings look like this:
|
||||||
//! 2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
//! `2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9`
|
||||||
//! first character of the string is the type of the binary data
|
//! first character of the string is the type of the binary data
|
||||||
//! in this case 2 means sha256
|
//! in this case 2 means sha256
|
||||||
//! the rest of the string is the hexadecimal representation of the binary data
|
//! the rest of the string is the hexadecimal representation of the binary data
|
||||||
|
@ -32,17 +28,33 @@
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use std::{fmt::Display, str::FromStr};
|
use std::{fmt::Display, hash::Hash, str::FromStr};
|
||||||
|
|
||||||
use enumflags2::{bitflags, BitFlags};
|
use digest::OutputSizeUser;
|
||||||
|
|
||||||
|
use jetstream_wireformat::Data;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
const SEPARATOR: char = 'ː';
|
use serde_json::json;
|
||||||
|
|
||||||
|
#[cfg(feature = "openapi")]
|
||||||
|
use utoipa::ToSchema;
|
||||||
|
use utoipa::{
|
||||||
|
openapi::{schema::SchemaType, SchemaFormat, Type},
|
||||||
|
PartialSchema,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Separator character for the OkId string representation
|
||||||
|
pub const SEPARATOR: char = 'ː';
|
||||||
|
|
||||||
#[cfg(feature = "blake3")]
|
#[cfg(feature = "blake3")]
|
||||||
/// blake3 module
|
/// blake3 module
|
||||||
pub mod blake3;
|
pub mod blake3;
|
||||||
|
/// fingerprint module
|
||||||
|
pub mod fingerprint;
|
||||||
|
#[cfg(feature = "git")]
|
||||||
|
/// git module
|
||||||
|
pub mod oid;
|
||||||
#[cfg(feature = "sha1")]
|
#[cfg(feature = "sha1")]
|
||||||
/// sha1 module
|
/// sha1 module
|
||||||
pub mod sha1;
|
pub mod sha1;
|
||||||
|
@ -62,6 +74,8 @@ pub mod uuid;
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Hash)]
|
||||||
pub(crate) enum BinaryType {
|
pub(crate) enum BinaryType {
|
||||||
|
// Unknown
|
||||||
|
Unknown = 0,
|
||||||
#[cfg(feature = "sha1")]
|
#[cfg(feature = "sha1")]
|
||||||
// Next bit means the size of the digest is of sha1 type
|
// Next bit means the size of the digest is of sha1 type
|
||||||
Sha1 = 1 << 0,
|
Sha1 = 1 << 0,
|
||||||
|
@ -80,6 +94,8 @@ pub(crate) enum BinaryType {
|
||||||
#[cfg(feature = "uuid")]
|
#[cfg(feature = "uuid")]
|
||||||
// UUID
|
// UUID
|
||||||
Uuid = 1 << 5,
|
Uuid = 1 << 5,
|
||||||
|
// Fingerprint
|
||||||
|
Fingerprint = 1 << 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<char> for BinaryType {
|
impl From<char> for BinaryType {
|
||||||
|
@ -97,7 +113,8 @@ impl From<char> for BinaryType {
|
||||||
'u' => Self::Ulid,
|
'u' => Self::Ulid,
|
||||||
#[cfg(feature = "uuid")]
|
#[cfg(feature = "uuid")]
|
||||||
'i' => Self::Uuid,
|
'i' => Self::Uuid,
|
||||||
_ => panic!("Invalid binary type"),
|
'f' => Self::Fingerprint,
|
||||||
|
_ => Self::Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +134,8 @@ impl BinaryType {
|
||||||
Self::Ulid => 'u',
|
Self::Ulid => 'u',
|
||||||
#[cfg(feature = "uuid")]
|
#[cfg(feature = "uuid")]
|
||||||
Self::Uuid => 'i',
|
Self::Uuid => 'i',
|
||||||
|
Self::Unknown => '0',
|
||||||
|
Self::Fingerprint => 'f',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,17 +155,99 @@ impl Display for BinaryType {
|
||||||
Self::Ulid => write!(f, "ulid"),
|
Self::Ulid => write!(f, "ulid"),
|
||||||
#[cfg(feature = "uuid")]
|
#[cfg(feature = "uuid")]
|
||||||
Self::Uuid => write!(f, "uuid"),
|
Self::Uuid => write!(f, "uuid"),
|
||||||
|
Self::Unknown => write!(f, "unknown"),
|
||||||
|
Self::Fingerprint => write!(f, "fingerprint"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The digest of the binary identifier
|
/// The digest of the binary identifier
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct OkId {
|
pub struct OkId {
|
||||||
hash_type: BinaryType,
|
hash_type: BinaryType,
|
||||||
/// The digest of the binary identifier
|
/// The digest of the binary identifier
|
||||||
digest: Digest,
|
digest: Digest,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// OkId scalar for graphql
|
||||||
|
#[cfg(feature = "graphql")]
|
||||||
|
async_graphql::scalar!(OkId);
|
||||||
|
|
||||||
|
#[cfg(feature = "openapi")]
|
||||||
|
impl PartialSchema for OkId {
|
||||||
|
fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
|
||||||
|
let mut o = utoipa::openapi::schema::Object::new();
|
||||||
|
o.schema_type = SchemaType::new(Type::String);
|
||||||
|
o.example = Some(json!(format!(
|
||||||
|
"2{SEPARATOR}00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
|
||||||
|
)
|
||||||
|
.to_string()));
|
||||||
|
let version = env!("CARGO_PKG_VERSION");
|
||||||
|
o.description = Some(format!(
|
||||||
|
r###"[OkId v{}](https://ok.software/ok/-/packages/cargo/okid/{})
|
||||||
|
"###,
|
||||||
|
version, version
|
||||||
|
));
|
||||||
|
o.format = Some(SchemaFormat::Custom("OkId".to_string()));
|
||||||
|
utoipa::openapi::RefOr::T(utoipa::openapi::schema::Schema::Object(o))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// OkId schema for openapi
|
||||||
|
#[cfg(feature = "openapi")]
|
||||||
|
impl ToSchema for OkId {
|
||||||
|
fn name() -> std::borrow::Cow<'static, str> {
|
||||||
|
"OkId".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for OkId {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (&self.digest, &other.digest) {
|
||||||
|
(Digest::Sha1(a), Digest::Sha1(b)) => a == b,
|
||||||
|
(Digest::Sha1(_), _) => false,
|
||||||
|
(Digest::Sha256(a), Digest::Sha256(b)) => a == b,
|
||||||
|
(Digest::Sha256(_), _) => false,
|
||||||
|
(Digest::Sha512(a), Digest::Sha512(b)) => a == b,
|
||||||
|
(Digest::Sha512(_), _) => false,
|
||||||
|
(Digest::Blake3(a), Digest::Blake3(b)) => a == b,
|
||||||
|
(Digest::Blake3(_), _) => false,
|
||||||
|
(Digest::Ulid(a), Digest::Ulid(b)) => a == b,
|
||||||
|
(Digest::Ulid(_), _) => false,
|
||||||
|
(Digest::Uuid(a), Digest::Uuid(b)) => a == b,
|
||||||
|
(Digest::Uuid(_), _) => false,
|
||||||
|
(Digest::Fingerprint(a), Digest::Fingerprint(b)) => a == b,
|
||||||
|
(Digest::Fingerprint(_), _) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for OkId {}
|
||||||
|
|
||||||
|
impl PartialOrd for OkId {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
match (&self.digest, &other.digest) {
|
||||||
|
(Digest::Ulid(a), Digest::Ulid(b)) => a.0.partial_cmp(&b.0),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for OkId {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.hash_type.hash(state);
|
||||||
|
match &self.digest {
|
||||||
|
Digest::Sha1(d) => d.hash(state),
|
||||||
|
Digest::Sha256(d) => d.hash(state),
|
||||||
|
Digest::Sha512(d) => d.hash(state),
|
||||||
|
Digest::Blake3(d) => d.hash(state),
|
||||||
|
Digest::Ulid(d) => d.hash(state),
|
||||||
|
Digest::Uuid(d) => d.hash(state),
|
||||||
|
Digest::Fingerprint(d) => d.hash(state),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Serialize for OkId {
|
impl Serialize for OkId {
|
||||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
serializer.serialize_str(&self.to_string())
|
serializer.serialize_str(&self.to_string())
|
||||||
|
@ -173,6 +274,8 @@ pub enum Error {
|
||||||
InvalidFormat,
|
InvalidFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Error {}
|
||||||
|
|
||||||
impl Display for Error {
|
impl Display for Error {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
@ -239,55 +342,16 @@ fn parse_okid(s: &str) -> Result<OkId, Error> {
|
||||||
hash_type,
|
hash_type,
|
||||||
digest: Digest::Uuid(rest.parse()?),
|
digest: Digest::Uuid(rest.parse()?),
|
||||||
}),
|
}),
|
||||||
|
BinaryType::Unknown => todo!(),
|
||||||
|
BinaryType::Fingerprint => Ok(OkId {
|
||||||
|
hash_type,
|
||||||
|
digest: Digest::Fingerprint(rest.parse()?),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bitflags]
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Hash)]
|
|
||||||
enum CommonSettings {
|
|
||||||
Git = 0b10000000,
|
|
||||||
Obfuscated = 0b01000000,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<char> for CommonSettings {
|
|
||||||
fn from(value: char) -> Self {
|
|
||||||
match value {
|
|
||||||
'g' => Self::Git,
|
|
||||||
'o' => Self::Obfuscated,
|
|
||||||
_ => panic!("Invalid common setting"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommonSettings {
|
|
||||||
fn char_code(&self) -> char {
|
|
||||||
match self {
|
|
||||||
Self::Git => 'g',
|
|
||||||
Self::Obfuscated => 'o',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for CommonSettings {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let settings = BitFlags::from_flag(*self);
|
|
||||||
let buf = "+".to_string();
|
|
||||||
let settings = settings.iter().fold(vec![], |acc, x| {
|
|
||||||
let mut acc = acc;
|
|
||||||
acc.push(x.char_code());
|
|
||||||
acc
|
|
||||||
});
|
|
||||||
|
|
||||||
let settings = settings
|
|
||||||
.iter()
|
|
||||||
.fold(String::new(), |acc, x| acc + &x.to_string());
|
|
||||||
|
|
||||||
write!(f, "{}", buf + settings.as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Digest of the binary identifier
|
/// Digest of the binary identifier
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum Digest {
|
enum Digest {
|
||||||
#[cfg(feature = "sha1")]
|
#[cfg(feature = "sha1")]
|
||||||
Sha1(crate::sha1::Sha1),
|
Sha1(crate::sha1::Sha1),
|
||||||
|
@ -301,11 +365,11 @@ enum Digest {
|
||||||
Ulid(crate::ulid::Ulid),
|
Ulid(crate::ulid::Ulid),
|
||||||
#[cfg(feature = "uuid")]
|
#[cfg(feature = "uuid")]
|
||||||
Uuid(crate::uuid::Uuid),
|
Uuid(crate::uuid::Uuid),
|
||||||
|
Fingerprint(crate::fingerprint::Fingerprint),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for OkId {
|
impl Display for OkId {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
// Write the binary type code
|
|
||||||
write!(f, "{}{}", self.hash_type.char_code(), SEPARATOR)?;
|
write!(f, "{}{}", self.hash_type.char_code(), SEPARATOR)?;
|
||||||
|
|
||||||
match &self.digest {
|
match &self.digest {
|
||||||
|
@ -321,13 +385,190 @@ impl Display for OkId {
|
||||||
Digest::Ulid(ulid) => ulid.fmt(f),
|
Digest::Ulid(ulid) => ulid.fmt(f),
|
||||||
#[cfg(feature = "uuid")]
|
#[cfg(feature = "uuid")]
|
||||||
Digest::Uuid(uuid) => uuid.fmt(f),
|
Digest::Uuid(uuid) => uuid.fmt(f),
|
||||||
|
Digest::Fingerprint(fingerprint) => fingerprint.fmt(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for OkId {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}{}", self.hash_type.char_code(), SEPARATOR)?;
|
||||||
|
|
||||||
|
match &self.digest {
|
||||||
|
#[cfg(feature = "sha1")]
|
||||||
|
Digest::Sha1(sha1) => std::fmt::Display::fmt(sha1, f),
|
||||||
|
#[cfg(feature = "sha2")]
|
||||||
|
Digest::Sha256(sha256) => std::fmt::Display::fmt(sha256, f),
|
||||||
|
#[cfg(feature = "sha3")]
|
||||||
|
Digest::Sha512(sha512) => std::fmt::Display::fmt(sha512, f),
|
||||||
|
#[cfg(feature = "blake3")]
|
||||||
|
Digest::Blake3(blake3) => std::fmt::Display::fmt(blake3, f),
|
||||||
|
#[cfg(feature = "ulid")]
|
||||||
|
Digest::Ulid(ulid) => std::fmt::Display::fmt(ulid, f),
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
Digest::Uuid(uuid) => std::fmt::Display::fmt(uuid, f),
|
||||||
|
|
||||||
|
Digest::Fingerprint(fingerprint) => std::fmt::Display::fmt(fingerprint, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IntoOkId trait, a common trait that OkId can be converted from
|
||||||
|
pub trait IntoOkId
|
||||||
|
where
|
||||||
|
Self: Into<OkId>,
|
||||||
|
{
|
||||||
|
/// Convert the type into an OkId
|
||||||
|
fn into_okid(self) -> OkId {
|
||||||
|
self.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OkId {
|
||||||
|
/// Convert the OkId into a byte slice
|
||||||
|
#[inline]
|
||||||
|
pub fn as_key(&self) -> &[u8] {
|
||||||
|
let fmtd = self.to_string();
|
||||||
|
let bytes = fmtd.as_bytes();
|
||||||
|
// SAFETY: the bytes are from a string, which is guaranteed to be valid utf8
|
||||||
|
unsafe { std::slice::from_raw_parts(bytes.as_ptr(), bytes.len()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// FromDigest trait, a common trait that OkId can be converted from
|
||||||
|
pub trait FromDigest: OutputSizeUser + digest::Digest + IntoOkId + Send {}
|
||||||
|
|
||||||
|
impl<T: digest::Digest + OutputSizeUser + IntoOkId + Send> FromDigest for T {}
|
||||||
|
|
||||||
|
impl jetstream_wireformat::WireFormat for OkId {
|
||||||
|
fn byte_size(&self) -> u32 {
|
||||||
|
// binary type + separator
|
||||||
|
1
|
||||||
|
// digest length
|
||||||
|
+ match self.digest {
|
||||||
|
Digest::Sha1(sha1) => sha1.0.len() as u32 ,
|
||||||
|
Digest::Sha256(sha256) => sha256.0.len() as u32 ,
|
||||||
|
Digest::Sha512(sha512) => sha512.0.len() as u32,
|
||||||
|
Digest::Blake3(blake3) => blake3.0.len() as u32,
|
||||||
|
Digest::Ulid(_ulid) => 128 / 8,
|
||||||
|
Digest::Uuid(_uuid) => 128 / 8,
|
||||||
|
Digest::Fingerprint(_fingerprint) => 64 / 8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||||
|
let c = self.hash_type.char_code() as u8;
|
||||||
|
u8::encode(&c, writer)?;
|
||||||
|
|
||||||
|
match &self.digest {
|
||||||
|
#[cfg(feature = "sha1")]
|
||||||
|
Digest::Sha1(sha1) => Data::encode(&Data(sha1.0.into()), writer)?,
|
||||||
|
#[cfg(feature = "sha2")]
|
||||||
|
Digest::Sha256(sha256) => Data::encode(&Data(sha256.0.into()), writer)?,
|
||||||
|
#[cfg(feature = "sha3")]
|
||||||
|
Digest::Sha512(sha512) => Data::encode(&Data(sha512.0.into()), writer)?,
|
||||||
|
#[cfg(feature = "blake3")]
|
||||||
|
Digest::Blake3(blake3) => Data::encode(&Data(blake3.0.into()), writer)?,
|
||||||
|
#[cfg(feature = "ulid")]
|
||||||
|
Digest::Ulid(ulid) => u128::encode(&ulid.0, writer)?,
|
||||||
|
#[cfg(feature = "uuid")]
|
||||||
|
Digest::Uuid(uuid) => {
|
||||||
|
u128::encode(&uuid.0, writer)?;
|
||||||
|
}
|
||||||
|
Digest::Fingerprint(fingerprint) => {
|
||||||
|
u64::encode(&fingerprint.0, writer)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||||
|
let binary_type = u8::decode(reader)?;
|
||||||
|
match BinaryType::from(binary_type as char) {
|
||||||
|
BinaryType::Unknown => Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::InvalidData,
|
||||||
|
format!("Unknown binary type: {}", binary_type as char),
|
||||||
|
)),
|
||||||
|
#[cfg(feature = "sha1")]
|
||||||
|
BinaryType::Sha1 => {
|
||||||
|
let data = Data::decode(reader)?;
|
||||||
|
let data = data.get(0..20).unwrap();
|
||||||
|
let mut buf = [0; 20];
|
||||||
|
if data.len() == 20 {
|
||||||
|
buf.copy_from_slice(data);
|
||||||
|
}
|
||||||
|
Ok(OkId {
|
||||||
|
hash_type: BinaryType::Sha1,
|
||||||
|
digest: Digest::Sha1(crate::sha1::Sha1(buf)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
#[cfg(feature = "sha2")]
|
||||||
|
BinaryType::Sha256 => {
|
||||||
|
let data = Data::decode(reader)?;
|
||||||
|
let data = data.get(0..32).unwrap();
|
||||||
|
let mut buf = [0; 32];
|
||||||
|
if data.len() == 32 {
|
||||||
|
buf.copy_from_slice(data);
|
||||||
|
}
|
||||||
|
Ok(OkId {
|
||||||
|
hash_type: BinaryType::Sha256,
|
||||||
|
digest: Digest::Sha256(crate::sha2::Sha256(buf)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BinaryType::Sha3_512 => {
|
||||||
|
let data = Data::decode(reader)?;
|
||||||
|
let data = data.get(0..64).unwrap();
|
||||||
|
let mut buf = [0; 64];
|
||||||
|
if data.len() == 64 {
|
||||||
|
buf.copy_from_slice(data);
|
||||||
|
}
|
||||||
|
Ok(OkId {
|
||||||
|
hash_type: BinaryType::Sha3_512,
|
||||||
|
digest: Digest::Sha512(crate::sha3::Sha512(buf)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BinaryType::Blake3 => {
|
||||||
|
let data = Data::decode(reader)?;
|
||||||
|
let data = data.get(0..32).unwrap();
|
||||||
|
let mut buf = [0; 32];
|
||||||
|
if data.len() == 32 {
|
||||||
|
buf.copy_from_slice(data);
|
||||||
|
}
|
||||||
|
Ok(OkId {
|
||||||
|
hash_type: BinaryType::Blake3,
|
||||||
|
digest: Digest::Blake3(crate::blake3::Blake3(buf)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BinaryType::Ulid => {
|
||||||
|
let data = u128::decode(reader)?;
|
||||||
|
Ok(OkId {
|
||||||
|
hash_type: BinaryType::Ulid,
|
||||||
|
digest: Digest::Ulid(crate::ulid::Ulid(data)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BinaryType::Uuid => {
|
||||||
|
let data = u128::decode(reader)?;
|
||||||
|
Ok(OkId {
|
||||||
|
hash_type: BinaryType::Uuid,
|
||||||
|
digest: Digest::Uuid(crate::uuid::Uuid(data)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BinaryType::Fingerprint => {
|
||||||
|
let data = u64::decode(reader)?;
|
||||||
|
Ok(OkId {
|
||||||
|
hash_type: BinaryType::Fingerprint,
|
||||||
|
digest: Digest::Fingerprint(crate::fingerprint::Fingerprint(data)),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod binary_id_tests {
|
mod okid_tests {
|
||||||
|
|
||||||
|
use jetstream_wireformat::JetStreamWireFormat;
|
||||||
#[cfg(feature = "sha1")]
|
#[cfg(feature = "sha1")]
|
||||||
use sha1::Digest as sha1digest;
|
use sha1::Digest as sha1digest;
|
||||||
|
|
||||||
|
@ -338,7 +579,7 @@ mod binary_id_tests {
|
||||||
let hasher = sha1::Sha1::new();
|
let hasher = sha1::Sha1::new();
|
||||||
let binary_id = OkId::from(hasher);
|
let binary_id = OkId::from(hasher);
|
||||||
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
||||||
1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709
|
1ːda39a3ee5e6b4b0d3255bfef95601890afd80709
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sha1")]
|
#[cfg(feature = "sha1")]
|
||||||
|
@ -348,7 +589,7 @@ mod binary_id_tests {
|
||||||
hasher.update(b"hello world");
|
hasher.update(b"hello world");
|
||||||
let binary_id = OkId::from(hasher);
|
let binary_id = OkId::from(hasher);
|
||||||
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
||||||
1ː002aae6c35c94fcfb415dbe95f408b9ce91ee846ed
|
1ː2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sha2")]
|
#[cfg(feature = "sha2")]
|
||||||
|
@ -358,7 +599,7 @@ mod binary_id_tests {
|
||||||
hasher.update(b"hello world");
|
hasher.update(b"hello world");
|
||||||
let binary_id = OkId::from(hasher);
|
let binary_id = OkId::from(hasher);
|
||||||
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
||||||
2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
2ːb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,41 +647,174 @@ mod binary_id_tests {
|
||||||
|
|
||||||
#[cfg(feature = "sha1")]
|
#[cfg(feature = "sha1")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_hello_world_sha1() {
|
fn test_parse_hello_world() {
|
||||||
let hash = "1ː002aae6c35c94fcfb415dbe95f408b9ce91ee846ed";
|
let seperator = super::SEPARATOR;
|
||||||
|
let hash = format!("1{seperator}2aae6c35c94fcfb415dbe95f408b9ce91ee846ed");
|
||||||
let binary_id = hash.parse::<OkId>().unwrap();
|
let binary_id = hash.parse::<OkId>().unwrap();
|
||||||
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
assert_eq!(
|
||||||
1ː002aae6c35c94fcfb415dbe95f408b9ce91ee846ed
|
binary_id.to_string(),
|
||||||
"###);
|
format!("1{seperator}2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "sha2")]
|
#[cfg(feature = "sha2")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_hello_world_sha256() {
|
fn test_parse_hello_world_sha256() {
|
||||||
let hash = "2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
|
let seperator = super::SEPARATOR;
|
||||||
|
let hash =
|
||||||
|
format!("2{seperator}b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9");
|
||||||
let binary_id = hash.parse::<OkId>().unwrap();
|
let binary_id = hash.parse::<OkId>().unwrap();
|
||||||
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
assert_eq!(
|
||||||
2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
binary_id.to_string(),
|
||||||
"###);
|
format!("2{seperator}b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "sha3")]
|
#[cfg(feature = "sha3")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_hello_world_sha3() {
|
fn test_parse_hello_world_sha3() {
|
||||||
let hash = "3ː840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a";
|
let seperator = super::SEPARATOR;
|
||||||
|
let hash = format!("3{seperator}840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a");
|
||||||
let binary_id = hash.parse::<OkId>().unwrap();
|
let binary_id = hash.parse::<OkId>().unwrap();
|
||||||
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
assert_eq!(
|
||||||
3ː840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a
|
binary_id.to_string(),
|
||||||
"###);
|
format!("3{seperator}840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "blake3")]
|
#[cfg(feature = "blake3")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_hello_world_blake3() {
|
fn test_parse_hello_world_blake3() {
|
||||||
let hash = "bːd74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24";
|
let seperator = super::SEPARATOR;
|
||||||
|
let hash =
|
||||||
|
format!("b{seperator}d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24");
|
||||||
let binary_id = hash.parse::<OkId>().unwrap();
|
let binary_id = hash.parse::<OkId>().unwrap();
|
||||||
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
assert_eq!(
|
||||||
bːd74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24
|
binary_id.to_string(),
|
||||||
"###);
|
format!("b{seperator}d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ulid")]
|
||||||
|
#[test]
|
||||||
|
fn test_parse_hello_world_ulid() {
|
||||||
|
let seperator = super::SEPARATOR;
|
||||||
|
let hash = format!("u{seperator}146907d25d66000035da136af2f988ca");
|
||||||
|
let binary_id = hash.parse::<OkId>().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
binary_id.to_string(),
|
||||||
|
format!("u{seperator}146907d25d66000035da136af2f988ca"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "sha1")]
|
||||||
|
#[test]
|
||||||
|
fn test_wireformat_hello_world_sha1() {
|
||||||
|
use jetstream_wireformat::WireFormat;
|
||||||
|
|
||||||
|
let mut hasher = sha1::Sha1::new();
|
||||||
|
hasher.update(b"hello world");
|
||||||
|
let binary_id = OkId::from(hasher);
|
||||||
|
let mut buf: Vec<u8> = vec![];
|
||||||
|
OkId::encode(&binary_id, &mut buf).unwrap();
|
||||||
|
let new_binary_id = OkId::decode(&mut buf.as_slice()).unwrap();
|
||||||
|
assert_eq!(binary_id.to_string(), new_binary_id.to_string(),);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "sha2")]
|
||||||
|
#[test]
|
||||||
|
fn test_wireformat_hello_world_sha256() {
|
||||||
|
use jetstream_wireformat::WireFormat;
|
||||||
|
|
||||||
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(b"hello world");
|
||||||
|
let binary_id = OkId::from(hasher);
|
||||||
|
let mut buf: Vec<u8> = vec![];
|
||||||
|
OkId::encode(&binary_id, &mut buf).unwrap();
|
||||||
|
let new_binary_id = OkId::decode(&mut buf.as_slice()).unwrap();
|
||||||
|
assert_eq!(binary_id.to_string(), new_binary_id.to_string(),);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "sha3")]
|
||||||
|
#[test]
|
||||||
|
fn test_wireformat_hello_world_sha3() {
|
||||||
|
use jetstream_wireformat::WireFormat;
|
||||||
|
|
||||||
|
let mut hasher = sha3::Sha3_512::new();
|
||||||
|
hasher.update(b"hello world");
|
||||||
|
let binary_id = OkId::from(hasher);
|
||||||
|
let mut buf: Vec<u8> = vec![];
|
||||||
|
OkId::encode(&binary_id, &mut buf).unwrap();
|
||||||
|
let new_binary_id = OkId::decode(&mut buf.as_slice()).unwrap();
|
||||||
|
assert_eq!(binary_id.to_string(), new_binary_id.to_string(),);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "blake3")]
|
||||||
|
#[test]
|
||||||
|
fn test_wireformat_hello_world_blake3() {
|
||||||
|
use jetstream_wireformat::WireFormat;
|
||||||
|
|
||||||
|
let mut hasher = blake3::Hasher::new();
|
||||||
|
hasher.update(b"hello world");
|
||||||
|
let binary_id = OkId::from(hasher);
|
||||||
|
let mut buf: Vec<u8> = vec![];
|
||||||
|
OkId::encode(&binary_id, &mut buf).unwrap();
|
||||||
|
let new_binary_id = OkId::decode(&mut buf.as_slice()).unwrap();
|
||||||
|
assert_eq!(binary_id.to_string(), new_binary_id.to_string(),);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test serde
|
||||||
|
#[cfg(feature = "sha1")]
|
||||||
|
#[test]
|
||||||
|
fn test_serde_hello_world_sha1() {
|
||||||
|
use insta::assert_snapshot;
|
||||||
|
|
||||||
|
let mut hasher = sha1::Sha1::new();
|
||||||
|
hasher.update(b"hello world");
|
||||||
|
let binary_id = OkId::from(hasher);
|
||||||
|
let serialized = serde_json::to_string_pretty(&binary_id).unwrap();
|
||||||
|
let deserialized: OkId = serde_json::from_str(&serialized).unwrap();
|
||||||
|
assert_eq!(binary_id.to_string(), deserialized.to_string(),);
|
||||||
|
assert_snapshot!(serialized, @r###""1ː2aae6c35c94fcfb415dbe95f408b9ce91ee846ed""###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "sha2")]
|
||||||
|
#[test]
|
||||||
|
fn test_serde_hello_world_sha256() {
|
||||||
|
use insta::assert_snapshot;
|
||||||
|
|
||||||
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(b"hello world");
|
||||||
|
let binary_id = OkId::from(hasher);
|
||||||
|
let serialized = serde_json::to_string_pretty(&binary_id).unwrap();
|
||||||
|
let deserialized: OkId = serde_json::from_str(&serialized).unwrap();
|
||||||
|
assert_eq!(binary_id.to_string(), deserialized.to_string(),);
|
||||||
|
assert_snapshot!(serialized, @r###""2ːb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9""###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(JetStreamWireFormat, Debug, Eq, PartialEq)]
|
||||||
|
pub struct Chunk(pub u64, pub OkId);
|
||||||
|
|
||||||
|
#[derive(JetStreamWireFormat, Debug, Eq, PartialEq)]
|
||||||
|
pub struct ChunkMap(pub Vec<Chunk>);
|
||||||
|
|
||||||
|
#[derive(JetStreamWireFormat, Debug, Eq, PartialEq)]
|
||||||
|
pub struct File(pub OkId, pub ChunkMap);
|
||||||
|
|
||||||
|
use jetstream_wireformat::wire_format_extensions::ConvertWireFormat;
|
||||||
|
#[cfg(feature = "sha1")]
|
||||||
|
#[test]
|
||||||
|
fn test_serde_file_sha1() {
|
||||||
|
let mut hasher = sha1::Sha1::new();
|
||||||
|
hasher.update(b"hello world");
|
||||||
|
let binary_id = OkId::from(hasher);
|
||||||
|
let chunk = Chunk(1, binary_id);
|
||||||
|
let chunk_map = ChunkMap(vec![chunk]);
|
||||||
|
let file = File(binary_id, chunk_map);
|
||||||
|
let mut byts = file.to_bytes();
|
||||||
|
let new_file = File::from_bytes(&mut byts).unwrap();
|
||||||
|
let mut _reader = std::io::Cursor::new(byts);
|
||||||
|
|
||||||
|
assert_eq!(file, new_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
32
src/oid.rs
Normal file
32
src/oid.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use crate::{sha1::Sha1, BinaryType, Digest};
|
||||||
|
|
||||||
|
use super::OkId;
|
||||||
|
|
||||||
|
impl From<git2::Oid> for OkId {
|
||||||
|
fn from(value: git2::Oid) -> Self {
|
||||||
|
let data = value.as_bytes();
|
||||||
|
let mut buf = [0; 20];
|
||||||
|
if data.len() == 20 {
|
||||||
|
buf.copy_from_slice(data);
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
hash_type: BinaryType::Sha1,
|
||||||
|
digest: Digest::Sha1(Sha1(buf)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_git_oid() {
|
||||||
|
let oid = git2::Oid::from_str("0123456789abcdef0123456789abcdef01234567").unwrap();
|
||||||
|
let okid: OkId = oid.into();
|
||||||
|
assert_eq!(
|
||||||
|
okid.to_string(),
|
||||||
|
"1ː800123456789abcdef0123456789abcdef01234567"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
49
src/sha1.rs
49
src/sha1.rs
|
@ -1,14 +1,14 @@
|
||||||
use std::{fmt::Display, str::FromStr};
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
use digest::core_api::CoreWrapper;
|
use digest::core_api::CoreWrapper;
|
||||||
use enumflags2::BitFlags;
|
|
||||||
|
|
||||||
use super::{BinaryType, CommonSettings, Digest, OkId};
|
use super::{BinaryType, Digest, IntoOkId, OkId};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub(super) struct Sha1(BitFlags<CommonSettings>, [u8; 20]);
|
pub(super) struct Sha1(pub(crate) [u8; 20]);
|
||||||
|
|
||||||
use sha1::Digest as sha1Digest;
|
use sha1::Digest as sha1Digest;
|
||||||
|
|
||||||
impl From<sha1::Sha1> for OkId {
|
impl From<sha1::Sha1> for OkId {
|
||||||
fn from(value: sha1::Sha1) -> Self {
|
fn from(value: sha1::Sha1) -> Self {
|
||||||
let data = value.finalize();
|
let data = value.finalize();
|
||||||
|
@ -17,25 +17,26 @@ impl From<sha1::Sha1> for OkId {
|
||||||
if data.len() == 20 {
|
if data.len() == 20 {
|
||||||
buf.copy_from_slice(data);
|
buf.copy_from_slice(data);
|
||||||
}
|
}
|
||||||
let empty: BitFlags<CommonSettings> = BitFlags::empty();
|
|
||||||
Self {
|
Self {
|
||||||
hash_type: BinaryType::Sha1,
|
hash_type: BinaryType::Sha1,
|
||||||
digest: Digest::Sha1(Sha1(empty, buf)),
|
digest: Digest::Sha1(Sha1(buf)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<sha1::Sha1Core> for OkId {
|
impl From<sha1::Sha1Core> for OkId {
|
||||||
fn from(value: sha1::Sha1Core) -> Self {
|
fn from(value: sha1::Sha1Core) -> Self {
|
||||||
CoreWrapper::from_core(value).into()
|
CoreWrapper::from_core(value).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IntoOkId for sha1::Sha1 {}
|
||||||
|
|
||||||
impl Display for Sha1 {
|
impl Display for Sha1 {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let settings = self.0;
|
let data = self.0;
|
||||||
let data = self.1;
|
let buf = &hex::encode(data);
|
||||||
let buf = hex::encode([settings.bits()]) + &hex::encode(data);
|
f.write_str(buf)?;
|
||||||
f.write_str(&buf)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,33 +45,9 @@ impl FromStr for Sha1 {
|
||||||
type Err = super::Error;
|
type Err = super::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let mut settings = BitFlags::empty();
|
|
||||||
let buf = hex::decode(s)?;
|
let buf = hex::decode(s)?;
|
||||||
let _ = buf.first().map(|&first| {
|
|
||||||
settings = BitFlags::from_bits_truncate(first);
|
|
||||||
});
|
|
||||||
let mut hash: [u8; 20] = [0; 20];
|
let mut hash: [u8; 20] = [0; 20];
|
||||||
hash.copy_from_slice(&buf[1..]);
|
hash.copy_from_slice(&buf[..]);
|
||||||
Ok(Sha1(settings, hash))
|
Ok(Sha1(hash))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sha1_to_string() {
|
|
||||||
let hasher = sha1::Sha1::new();
|
|
||||||
let binary_id = OkId::from(hasher);
|
|
||||||
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
|
|
||||||
1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sha1_from_str() {
|
|
||||||
let hash = "1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709";
|
|
||||||
let _binary_id: OkId = hash.parse().unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
26
src/sha2.rs
26
src/sha2.rs
|
@ -1,13 +1,11 @@
|
||||||
use enumflags2::BitFlags;
|
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
use std::{fmt::Display, str::FromStr};
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
use crate::OkId;
|
use crate::OkId;
|
||||||
|
|
||||||
use super::CommonSettings;
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub(super) struct Sha256(pub(crate) [u8; 32]);
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
||||||
pub(super) struct Sha256(BitFlags<CommonSettings>, [u8; 32]);
|
|
||||||
impl From<sha2::Sha256> for OkId {
|
impl From<sha2::Sha256> for OkId {
|
||||||
fn from(value: sha2::Sha256) -> Self {
|
fn from(value: sha2::Sha256) -> Self {
|
||||||
let data = value.finalize();
|
let data = value.finalize();
|
||||||
|
@ -16,20 +14,20 @@ impl From<sha2::Sha256> for OkId {
|
||||||
if data.len() == 32 {
|
if data.len() == 32 {
|
||||||
buf.copy_from_slice(data);
|
buf.copy_from_slice(data);
|
||||||
}
|
}
|
||||||
let empty: BitFlags<CommonSettings> = BitFlags::empty();
|
|
||||||
Self {
|
Self {
|
||||||
hash_type: super::BinaryType::Sha256,
|
hash_type: super::BinaryType::Sha256,
|
||||||
digest: super::Digest::Sha256(Sha256(empty, buf)),
|
digest: super::Digest::Sha256(Sha256(buf)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl super::IntoOkId for sha2::Sha256 {}
|
||||||
|
|
||||||
impl Display for Sha256 {
|
impl Display for Sha256 {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let settings = self.0;
|
let data = self.0;
|
||||||
let data = self.1;
|
let buf = &hex::encode(data);
|
||||||
let buf = hex::encode([settings.bits()]) + &hex::encode(data);
|
f.write_str(buf)?;
|
||||||
f.write_str(&buf)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,13 +36,9 @@ impl FromStr for Sha256 {
|
||||||
type Err = super::Error;
|
type Err = super::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let mut settings = BitFlags::empty();
|
|
||||||
let buf = hex::decode(s)?;
|
let buf = hex::decode(s)?;
|
||||||
let _ = buf.first().map(|&first| {
|
|
||||||
settings = BitFlags::from_bits_truncate(first);
|
|
||||||
});
|
|
||||||
let mut hash: [u8; 32] = [0; 32];
|
let mut hash: [u8; 32] = [0; 32];
|
||||||
hash.copy_from_slice(&buf[1..]);
|
hash.copy_from_slice(&buf[..]);
|
||||||
Ok(Sha256(settings, hash))
|
Ok(Sha256(hash))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,9 @@ use sha3::Digest;
|
||||||
|
|
||||||
use super::OkId;
|
use super::OkId;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub(super) struct Sha512([u8; 64]);
|
pub(super) struct Sha512(pub(super) [u8; 64]);
|
||||||
|
|
||||||
impl From<sha3::Sha3_512> for OkId {
|
impl From<sha3::Sha3_512> for OkId {
|
||||||
fn from(value: sha3::Sha3_512) -> Self {
|
fn from(value: sha3::Sha3_512) -> Self {
|
||||||
let data = value.finalize();
|
let data = value.finalize();
|
||||||
|
@ -23,6 +24,8 @@ impl From<sha3::Sha3_512> for OkId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl super::IntoOkId for sha3::Sha3_512 {}
|
||||||
|
|
||||||
impl From<sha3::Sha3_512Core> for OkId {
|
impl From<sha3::Sha3_512Core> for OkId {
|
||||||
fn from(value: sha3::Sha3_512Core) -> Self {
|
fn from(value: sha3::Sha3_512Core) -> Self {
|
||||||
CoreWrapper::from_core(value).into()
|
CoreWrapper::from_core(value).into()
|
||||||
|
|
12
src/ulid.rs
12
src/ulid.rs
|
@ -2,8 +2,8 @@ use std::fmt::Display;
|
||||||
|
|
||||||
use crate::OkId;
|
use crate::OkId;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub(super) struct Ulid(u128);
|
pub(super) struct Ulid(pub(super) u128);
|
||||||
|
|
||||||
impl From<ulid::Ulid> for OkId {
|
impl From<ulid::Ulid> for OkId {
|
||||||
fn from(value: ulid::Ulid) -> Self {
|
fn from(value: ulid::Ulid) -> Self {
|
||||||
|
@ -21,6 +21,8 @@ impl Display for Ulid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl super::IntoOkId for ulid::Ulid {}
|
||||||
|
|
||||||
impl std::str::FromStr for Ulid {
|
impl std::str::FromStr for Ulid {
|
||||||
type Err = crate::Error;
|
type Err = crate::Error;
|
||||||
|
|
||||||
|
@ -31,3 +33,9 @@ impl std::str::FromStr for Ulid {
|
||||||
Ok(Ulid(u128::from_be_bytes(hash)))
|
Ok(Ulid(u128::from_be_bytes(hash)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Ulid> for ulid::Ulid {
|
||||||
|
fn from(val: Ulid) -> Self {
|
||||||
|
ulid::Ulid(val.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
13
src/uuid.rs
13
src/uuid.rs
|
@ -2,8 +2,9 @@ use std::fmt::Display;
|
||||||
|
|
||||||
use crate::OkId;
|
use crate::OkId;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub(super) struct Uuid(u128);
|
pub(super) struct Uuid(pub(super) u128);
|
||||||
|
|
||||||
impl From<uuid::Uuid> for OkId {
|
impl From<uuid::Uuid> for OkId {
|
||||||
fn from(value: uuid::Uuid) -> Self {
|
fn from(value: uuid::Uuid) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -20,6 +21,8 @@ impl Display for Uuid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl super::IntoOkId for uuid::Uuid {}
|
||||||
|
|
||||||
impl std::str::FromStr for Uuid {
|
impl std::str::FromStr for Uuid {
|
||||||
type Err = crate::Error;
|
type Err = crate::Error;
|
||||||
|
|
||||||
|
@ -30,3 +33,9 @@ impl std::str::FromStr for Uuid {
|
||||||
Ok(Uuid(u128::from_be_bytes(hash)))
|
Ok(Uuid(u128::from_be_bytes(hash)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Uuid> for uuid::Uuid {
|
||||||
|
fn from(val: Uuid) -> Self {
|
||||||
|
uuid::Uuid::from_u128(val.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue