Git · dadoum.zone
Repositories
Help
Report an Issue
apple-crates
Code
Commits
Branches
Tags
Search
Tree:
2ab8bf0
Branches
Tags
main
apple-crates
CODE_STYLE.md
Add instructions for agents, and a few minor API adjustments and additions.
Dadoum
commited
2ab8bf0
at 2026-10-27 03:57:30
CODE_STYLE.md
Blame
History
Raw
# Code style The style of the hand-written `adi`, `grandslam` and `xcode` crates. It applies to new code in apple-crates and Antarctic. When this file and those crates disagree, the crates win. ## Naming - Acronyms stay upper-case in types, traits and variants: `ADIError`, `HTTPSession`, `URLBag`, `TeamID`. Apple names with a lower-case prefix only capitalise the first letter: `IOS`, `TvOS`, `ICloud`. In snake_case, each acronym is one lower-case word: `ds_id`, `set_idms_routing`. - Locals and fields are spelled out in full. Keep Apple's wire names (`spim`, `cpim`, `ptm`, `tk`, `mid`, `otp`). Raw bytes before encoding take a `_b` suffix. - Functions start with a verb. A short entry point delegates to `<base>_with_<thing>` variants (`http_session` → `http_session_with_idms_env`). Request builders are `<layer>_request_builder`. Wire types are named after their endpoint. - Lifetimes are `'lt` (and `'adi`), or `'_` when no name is needed. Never mix them with `'a` in a file. ## Types and API shape - Plain data has `pub` fields and is built with struct literals: no builders, setters or getters. - Tokens and identifiers are tuple newtypes with a private field, `From<String>` and `AsRef<str>`. - Session layers wrap the layer below (`pub http_session: Inner` plus one credential, `new(inner, credential)`) and forward its request builders by hand. No `Deref`, no generic service traits. - Small traits, with associated consts or types. Generics only for compile-time typing; `&dyn Trait` for runtime providers. Bounds inline, no `where` clauses. Implement `From`, never `Into`. - Protocol states that aren't failures are variants of an outcome enum returned in `Ok`. - Plain `pub async fn` with sequential awaits. Libraries spawn nothing, pick no runtime, and keep ADI and crypto calls synchronous. - Derive only what's needed, in this order: `Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize`. Types holding credentials don't derive `Debug`. - Wire structs use `#[serde(rename_all = "camelCase")]`. String-backed enums map to `&'static str` in one `match`. - Native resources are linear guards: `#[must_use]` and a `Drop` that panics unless `std::thread::panicking()`. ## Errors - `thiserror` everywhere, one enum per operation or module, living next to the code returning it. - Variants are named after the layer that failed (`Network`, `Anisette`, `Parsing`, `Apple`) and carry the source error or the offending `Dictionary`. Server failures are struct variants. Mark the rest with `// vvv Internal errors vvv`. - Messages are sentences: what failed, then `: {0}`, no trailing period. - `map_err` takes a function path (`map_err(AuthError::Parsing)`). A crate result alias is welcome. ## Control flow - No `let ... else`, and few early returns. Prefer `if`/`match` as tail expressions, tuple matches and or-patterns (`None | Some(0) => Ok(())`). - Shadow names through a pipeline, and annotate `let`s instead of using a turbofish. - Combinators take function paths when one fits (`.and_then(Value::as_string)`); use `.map(..).transpose()?`. - One fluent chain per HTTP request, ending with `.error_for_status()?` and `.bytes().await?`, then parsed into an annotated binding. Build plists with `dict!`/`array!` and send them with `plist_to_body`/`dict_to_body`. - No `.unwrap()` in library code. `expect` only for invariants, with a sentence message, and a `// UNWRAP safety:` comment when it isn't obvious. - Edition 2024 `unsafe` blocks wrap just the unsafe expression. Out-parameters use `MaybeUninit`. ## Layout and comments - `rustfmt`, run per package. Long `#[error]` attributes and comments stay on one line. - Inline format captures (`"{name}"`); `.to_string()`/`String::from`, not `.to_owned()`. - Match arms say `TypeName::Variant`, not `Self::Variant`. - One `use` block in rustfmt order, without nested braces; items used once go by full path. - Flat crates: `foo.rs` plus `foo/`, never `mod.rs`; private modules re-exported with `pub use foo::*`; files of roughly 300–500 lines. - Short `///` docs on public entry points only, no `//!` essays or rustdoc templates. - Inline comments are first person and informal, explaining Apple quirks and uncertainty, never restating the code. Tags: `// TODO:`, `// HACK`, `// UNWRAP safety:`. - Tests: inline `#[cfg(test)] mod tests { use super::*; }` with tiny mocks. Network crates get runnable examples reading credentials from environment variables. - Libraries rarely log (`warn!` for surprises), and never log credentials or decrypted dictionaries.