diff --git a/.github/workflows/dusk_ci.yml b/.github/workflows/dusk_ci.yml index d079199..acb0bd6 100644 --- a/.github/workflows/dusk_ci.yml +++ b/.github/workflows/dusk_ci.yml @@ -1,16 +1,26 @@ -on: [pull_request] +on: + pull_request: + push: + branches: + - main name: Continuous integration jobs: - code_analysis: - name: Code Analysis - uses: dusk-network/.github/.github/workflows/code-analysis.yml@main - - dusk_analysis: - name: Dusk Analyzer - uses: dusk-network/.github/.github/workflows/dusk-analysis.yml@main + code-quality: + name: Code quality + uses: dusk-network/.github/.github/workflows/run-make.yml@main + with: + make_target: cq test: - name: Tests - uses: dusk-network/.github/.github/workflows/run-tests.yml@main + name: Run tests + uses: dusk-network/.github/.github/workflows/run-make.yml@main + with: + make_target: test + + no-std: + name: Run no-std tests + uses: dusk-network/.github/.github/workflows/run-make.yml@main + with: + make_target: no-std diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..48c4d82 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,90 @@ +# dusk-bytes + +Serialization traits using const generics for fixed-size types. Workspace with two `no_std` crates: core serialization traits and a companion proc-macro for hex formatting. This is a foundational dependency for most Dusk repos — changes here ripple widely. + +## Repository Map + +``` +bytes/ +├── dusk-bytes/ # dusk-bytes — Serializable, DeserializableSlice, Read/Write, hex parsing +│ ├── src/ +│ │ ├── lib.rs # Re-exports, crate attributes +│ │ ├── serialize.rs # Serializable, DeserializableSlice, Read, Write traits +│ │ ├── parse.rs # ParseHexStr trait, const hex() function +│ │ ├── errors.rs # Error enum, BadLength/InvalidChar traits +│ │ └── primitive.rs # Serializable impls for integer primitives (u8..u128, i8..i128) +│ └── tests/ +├── derive-hex/ # derive-hex — #[derive(Hex)] and #[derive(HexDebug)] proc macros +│ ├── src/ +│ │ └── lib.rs # LowerHex, UpperHex, Debug derive implementations +│ └── tests/ +├── Makefile # Build targets (run `make help`) +└── rustfmt.toml +``` + +## Commands + +Run `make help` to see all available targets. + +## Architecture + +### Core Traits (`dusk-bytes`) + +- **`Serializable`** — defines `from_bytes(&[u8; N])` and `to_bytes() -> [u8; N]` for fixed-size serialization. The const generic `N` is the wire size. +- **`DeserializableSlice`** — auto-implemented for all `Serializable` types. Adds `from_slice(&[u8])` (with length check) and `from_reader()` (streaming). +- **`Read` / `Write`** — minimal byte-oriented IO traits (not `std::io`). `Read` is implemented for `&[u8]` (advances the slice), `Write` for `&mut [u8]`. +- **`ParseHexStr`** — auto-implemented for all `Serializable` types. Parses hex strings into the target type. +- **`hex::()`** — const function for compile-time hex-to-bytes conversion. + +### Proc Macros (`derive-hex`) + +- **`#[derive(Hex)]`** — generates `LowerHex` and `UpperHex` implementations using the type's `to_bytes()` method. +- **`#[derive(HexDebug)]`** — generates `Hex` plus a `Debug` implementation that delegates to hex formatting. + +### Key Design Points + +- All serialization is little-endian (see primitive impls). +- `derive-hex` is a proc-macro crate — it cannot be built for `no_std` targets like `thumbv6m-none-eabi`. The `no-std` Makefile target only builds `dusk-bytes`. +- No feature flags — both crates expose their full API unconditionally. + +## Conventions + +- **`no_std`**: Both crates. Do not add `std` dependencies. +- **Edition 2024**: MSRV 1.85. +- **Wide downstream impact**: This crate is a dependency of most Dusk repos. Check `Cargo.lock` in downstream repos before releasing. See the Change Propagation table below. + +## Change Propagation + +| Changed | Also verify | +|---------|-------------| +| `dusk-bytes` or `derive-hex` | Most repos — check `Cargo.lock` for users. Key dependents: `bls12_381`, `jubjub`, `phoenix`, `safe`, `Poseidon252`, `merkle`, `rusk` | + +## Git Conventions + +- Default branch: `main` +- License: MPL-2.0 + +### Commit messages + +Format: `: ` — imperative mood, capitalize first word after colon. + +**One commit per crate per concern.** Each commit touches exactly one crate and one logical concern. Never bundle changes to different crates in one commit, and don't mix unrelated changes within the same crate either. + +Canonical scopes: + +| Scope | Crate/Directory | +|-------|----------------| +| `dusk-bytes` | `dusk-bytes/` | +| `derive-hex` | `derive-hex/` | +| `workspace` | Root `Cargo.toml`, root Makefile | +| `ci` | `.github/workflows/` | +| `chore` | Makefile, rustfmt, etc. | + +Examples: +- `dusk-bytes: Add Read impl for Vec` +- `derive-hex: Fix category slugs` +- `workspace: Update edition to 2024` + +### Changelog + +`derive-hex` has a `CHANGELOG.md`. Add entries under `[Unreleased]` using [keep-a-changelog](https://keepachangelog.com/) format. If a change traces to a GitHub issue, reference it as a link: `[#42](https://github.com/dusk-network/dusk-bytes/issues/42)`. Only link to GitHub issues — do not reference any other tracking system. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000..47dc3e3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dd11ab0 --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +help: ## Display this help screen + @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ + awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +fmt: ## Format code (requires nightly) + @rustup component add --toolchain nightly rustfmt 2>/dev/null || true + @cargo +nightly fmt --all $(if $(CHECK),-- --check,) + +clippy: ## Run clippy + @cargo clippy --all-features -- -D warnings + +cq: ## Run code quality checks (formatting + clippy) + @$(MAKE) fmt CHECK=1 + @$(MAKE) clippy + +check: ## Type-check + @cargo check --all-features + +test: ## Run tests + @cargo test --release + +no-std: ## Verify no_std compatibility on bare-metal target + @rustup target add thumbv6m-none-eabi 2>/dev/null || true + @cargo build --no-default-features -p dusk-bytes --target thumbv6m-none-eabi + +doc: ## Generate docs + @cargo doc --no-deps + +clean: ## Clean build artifacts + @cargo clean + +.PHONY: help fmt clippy cq check test no-std doc clean diff --git a/dusk-bytes/tests/common/mod.rs b/dusk-bytes/tests/common/mod.rs index 2467c19..401412a 100644 --- a/dusk-bytes/tests/common/mod.rs +++ b/dusk-bytes/tests/common/mod.rs @@ -4,9 +4,7 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use dusk_bytes::{BadLength, InvalidChar, Serializable}; - -use dusk_bytes::HexDebug; +use dusk_bytes::{BadLength, HexDebug, InvalidChar, Serializable}; #[derive(HexDebug)] pub struct Beef {} diff --git a/dusk-bytes/tests/parse_test.rs b/dusk-bytes/tests/parse_test.rs index fd8b080..7d33981 100644 --- a/dusk-bytes/tests/parse_test.rs +++ b/dusk-bytes/tests/parse_test.rs @@ -6,7 +6,6 @@ mod common; use common::{Beef, BeefError}; - use dusk_bytes::ParseHexStr; #[test] diff --git a/dusk-bytes/tests/serialize_test.rs b/dusk-bytes/tests/serialize_test.rs index 7e48639..6cca0d4 100644 --- a/dusk-bytes/tests/serialize_test.rs +++ b/dusk-bytes/tests/serialize_test.rs @@ -5,10 +5,10 @@ // Copyright (c) DUSK NETWORK. All rights reserved. mod common; -use common::{Beef, BeefError}; +use std::fmt::Debug; +use common::{Beef, BeefError}; use dusk_bytes::{DeserializableSlice, Error, Serializable}; -use std::fmt::Debug; #[test] fn expected_size() { diff --git a/rustfmt.toml b/rustfmt.toml index df99c69..6e27c84 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1 +1,6 @@ +unstable_features = true +group_imports = "StdExternalCrate" +imports_granularity = "Module" +use_field_init_shorthand = true +wrap_comments = true max_width = 80