Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Devolutions/IronRDP/llms.txt
Use this file to discover all available pages before exploring further.
Introduction
This document explains the architectural invariants and design principles that guide IronRDP development. These are not merely suggestions - they are enforced rules that ensure the codebase remains maintainable, secure, and performant.An architectural invariant is a property that must hold true at all times. Violating these invariants can compromise security, portability, or the ability to maintain the codebase.
Core Principles
I/O Separation
Why No I/O in Core?
Separating protocol logic from I/O operations provides several critical benefits:- Testability: Pure protocol logic can be tested deterministically without mocking sockets, files, or system calls
- Fuzzing: Fuzz targets can feed arbitrary byte sequences directly to protocol parsers without I/O overhead
- Portability: Core libraries work in any environment - embedded systems, WebAssembly, operating system kernels
- Security: Smaller attack surface by eliminating I/O-related vulnerabilities from protocol code
Dependency Injection Pattern
When runtime information is needed (hostname, current time, random values), use dependency injection:No Platform-Dependent Code
The RDP protocol itself is platform-agnostic. Platform-specific implementations belong in extra tier crates:ironrdp-cliprdr-native- native clipboard integrationironrdp-rdpdr-native- native device redirectionironrdp-rdpsnd-native- native audio output
no_std Compatibility
Feature Flag Pattern
Quality Invariants
Mandatory Fuzzing
RDP is a network protocol exposed to potentially malicious input. Fuzzing is not optional for security-critical parsing code. Fuzz targets location:fuzz/
Running fuzzing:
Test at Boundaries
Architecture Invariant: Tests focus on API boundaries (public APIs of libraries) rather than implementation details.
ironrdp-testsuite-core- for core tier cratesironrdp-testsuite-extra- for extra tier crates
No External Dependencies in Tests
Tests must:- Not require internet connectivity
- Not depend on specific file system structures
- Not rely on system services or daemons
- Be deterministic and repeatable
- Use
include_bytes!()for test data - Use
expect-testfor snapshot testing - Use
proptestfor property-based testing with controlled randomness
Dependency Management
Minimal Dependencies in Core
Examples of acceptable dependencies:bitflags- efficient bit flag handlingder-parser- X.509 certificate parsing (required for RDP security)- Cryptographic primitives (
md5,sha1)
- HTTP clients
- Logging frameworks (use
tracingwith dependency injection) - Serialization frameworks (implement
Encode/Decodedirectly)
No Proc-Macro Dependencies
Rationale: Compilation time is a multiplier for everything. Proc-macros are a major compilation bottleneck. Research by Google engineers shows build latency significantly impacts developer productivity. Exceptions:thiserror may be used for error types, but only if the ergonomic benefit clearly outweighs the compilation cost.
No [workspace.dependencies] for External Crates
Rationale: release-plz cannot detect that a dependency has been updated in a way warranting a version bump if no commit touches a file associated with the crate.
Phasing Out Legacy Dependencies
Performance Principles
Avoid Monomorphization Bloat
The Problem with Generic Code
Rust uses monomorphization - generating separate machine code for each concrete type a generic function is called with. This provides excellent runtime performance but has costs:- Compilation time: Each instantiation is compiled separately
- Binary size: Code is duplicated for each type
- Parallelism: More units to compile can saturate the CPU
Solution: Delegate to Dynamic Dispatch
Avoid Premature Polymorphism
AsRef polymorphism may be worth it for widely-used libraries where ergonomics matter significantly.
Allocation Awareness
Avoid unnecessary allocations, especially in hot paths:Zero-Copy Parsing
UseReadCursor and WriteCursor for efficient, no_std-compatible I/O:
CI/CD Invariants
Local CI Equivalence
Rationale: Developers should be able to validate their changes locally with confidence before pushing. Usage:Test Suite Isolation
Rationale: Keeps iteration time short when working on core protocol logic.Error Handling Standards
Error Type Requirements
Following Rust conventions:- Libraries: Use concrete error types (hand-crafted or
thiserror) - Binaries: Use
anyhow::Errorfor catch-all error handling
Error Message Formatting
Error messages must be:
- Short and concise
- Lowercase (no capital letter at start)
- No trailing punctuation
API Boundary Rules
Certain crates are designated as API Boundaries - public interfaces that external code depends on:Core Tier (All are API Boundaries)
ironrdp(meta crate)ironrdp-coreironrdp-pduironrdp-connectorironrdp-session- And others (see Crate Tiers)
Extra Tier (Selected)
ironrdp-blockingironrdp-asyncironrdp-tokioironrdp-futuresironrdp-web(WASM module)
Special Considerations at Boundaries
Remember: Rules at the boundary are different
- Breaking changes require careful consideration and major version bumps
- Documentation must be comprehensive
- Performance characteristics become public contract
- Error types become part of the API
Internal Tier Boundaries
Internal crates (ironrdp-testsuite-*, ironrdp-fuzzing, xtask) are free to change as needed for project maintenance.
Summary
These design principles ensure IronRDP remains: ✅ Secure - through mandatory fuzzing and small attack surface✅ Portable - via
no_std support and I/O separation✅ Maintainable - with clear boundaries and minimal dependencies
✅ Fast to compile - by avoiding monomorphization and proc-macros
✅ Testable - through deterministic, reproducible tests When in doubt, refer back to these principles and the ARCHITECTURE.md document in the repository.
Further Reading
Architecture Overview
High-level architecture and design philosophy
Crate Tiers
Detailed breakdown of each tier and its crates

