Instruction file imported from zenbase-ai/llml (
.cursor/rules/rs.mdc). Copyright stays with the author.
Rust Coding Rules for LLML Project
These guidelines are designed to maintain the existing quality, style, and architectural patterns of the codebase.
Project Structure & Modules
- Public API (
src/lib.rs): Thesrc/lib.rsfile is the public face of the library. It should only contain the public API (llml,llml_with_options,Optionsstruct) and its associated documentation and unit tests. - Core Logic (
src/formatters.rs): All internal formatting logic should reside in thesrc/formatters.rsmodule. Functions within this module should remain private to the crate (i.e., not marked withpub). - Tests:
- Unit Tests: Place unit tests within the module they are testing, using a
#[cfg(test)] mod tests { ... }block. - Integration Tests: Place integration tests in the
tests/directory. These tests should only call the public API fromlib.rs.
- Unit Tests: Place unit tests within the module they are testing, using a
- Examples: Add new usage examples to the
examples/directory.
Coding Style & Formatting
- Formatting: All code must be formatted with
rustfmtusing the default settings. - Naming Conventions:
- Functions & Variables: Use
snake_case(e.g.,format_value,kebab_key). - Types (Structs, Enums): Use
PascalCase(e.g.,Options). - Constants & Statics: Use
SCREAMING_SNAKE_CASE(e.g.,MULTI_HYPHEN_RE).
- Functions & Variables: Use
- Clarity: Prioritize clear, readable code. Use descriptive variable names.
API Design & Patterns
- Public Functions: The primary public functions are
llml(for default options) andllml_with_options(for custom formatting). Maintain this clear separation. - Configuration: All configuration should be passed via the
Optionsstruct. When adding new configuration, extend this struct. - Optional Configuration: Use
Option<Options>for thellml_with_optionsfunction signature. Useoptions.unwrap_or_default()to handle theNonecase. - Immutability: Prefer immutable variables (
let) over mutable ones (let mut) unless mutability is strictly necessary (e.g., for builders or accumulators). - Performance:
- Pass complex types like
ValueandOptionsby reference (&) to avoid unnecessary clones. - For expensive initializations that can be shared (like
Regex), usestd::sync::OnceLock.
- Pass complex types like
Type Usage & Data Handling
- Primary Data Type: The library's core data input is
&serde_json::Value. This ensures compatibility with any data that can be serialized to JSON. - String Handling:
- Use
format!for constructing simple strings. - For building strings from multiple parts in a loop, collect parts into a
Vec<String>and then useparts.join("")for efficiency. - Use
&stras function arguments for string slices instead ofStringwhere possible.
- Use
- Recursion: The core formatting logic is recursive. New formatting rules should be integrated into the existing recursive
format_valueandformat_key_valuefunctions.
Error Handling
- No
ResultTypes: The library's public API returns aString. It does not return aResultas it's designed to format already-validated data structures. This convention should be maintained. - Panics: Avoid panics in the library code. The only acceptable use is for a one-time initialization failure in
OnceLockwhere a hardcoded value (like a regex pattern) is invalid, as this indicates a critical programmer error.
Testing
- Comprehensive Coverage: Every new feature or bug fix must be accompanied by tests.
- Unit Tests: Test internal logic, such as individual formatting helpers (e.g.,
to_kebab_case), in the module's test block. - Integration Tests: Test the public API from a user's perspective in
tests/integration_test.rs. Cover a wide range of inputs, including edge cases (empty strings, empty collections,null,false,0). - Test Data: Use the
serde_json::json!macro to createValueinstances for tests, as it is concise and readable. - Assertions:
- Use
assert_eq!for exact string matches. - When testing the output of a
serde_json::Mapwhere key order is not guaranteed, use multipleassert!(result.contains(...))calls to verify that all expected parts are present in the output string.
- Use
Documentation
- Public API: All public items (
lib.rs) must have clear, comprehensive doc comments (///). Explain what the function does, its parameters, and provide a simple usage example in arustdoccode block. - Module-Level Docs: Use
/*! ... */for module-level documentation that explains the purpose of the module. - Internal Comments: Use comments (
//) sparingly to explain the why behind complex or non-obvious code, not the what. - README: Keep
rs/README.mdupdated with any new features or API changes.
