waddling-errors 0.7.3

Structured, secure-by-default diagnostic codes for distributed systems with no_std and role-based documentation
Documentation
//! Storage Component
//!
//! S3-compatible object storage - file uploads, downloads, versioning, presigned URLs.

use crate::primaries::Primary;
use waddling_errors::ComponentIdDocumented;
use waddling_errors::prelude::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Storage;

impl ComponentId for Storage {
    fn as_str(&self) -> &'static str {
        "Storage"
    }
}

impl ComponentIdDocumented for Storage {
    fn description(&self) -> Option<&'static str> {
        Some(
            "S3-compatible object storage. Handles file uploads, downloads, versioning, \
              and presigned URL generation.",
        )
    }

    fn examples(&self) -> &'static [&'static str] {
        &[
            "E.Storage.Permission.008: S3 bucket access denied",
            "C.Storage.Data.025: Object integrity check failed (corrupt upload)",
            "K.Storage.Data.999: Multipart upload completed successfully",
        ]
    }

    fn tags(&self) -> &'static [&'static str] {
        &["files", "s3", "objects"]
    }
}

// ============================================================================
// Error Code Definitions
// ============================================================================

/// S3 bucket access denied (.008 = DENIED)
pub const ERR_PERMISSION_DENIED: Code<Storage, Primary> =
    Code::error(Storage, Primary::Permission, 8);

/// CRITICAL: Object corruption detected (.025 = CORRUPTED)
pub const CRIT_DATA_CORRUPTED: Code<Storage, Primary> = Code::critical(Storage, Primary::Data, 25);

/// Object already exists - upload conflict (.022 = ALREADYEXISTS)
pub const ERR_DATA_ALREADYEXISTS: Code<Storage, Primary> = Code::error(Storage, Primary::Data, 22);

/// Object not found in storage (.021 = NOTFOUND)
pub const ERR_DATA_NOTFOUND: Code<Storage, Primary> = Code::error(Storage, Primary::Data, 21);

/// Multipart upload completed successfully (.999 = COMPLETE)
pub const COMPLETE_UPLOAD: Code<Storage, Primary> = Code::completed(Storage, Primary::Data, 999);

/// Storage operation trace - debugging enabled (.100 = Custom trace)
pub const TRACE_OPERATION: Code<Storage, Primary> = Code::trace(Storage, Primary::Data, 100);

// ============================================================================
// Component Registration
// ============================================================================

#[cfg(feature = "doc-gen")]
pub fn register_component(generator: &mut waddling_errors::doc_generator::DocRegistry) {
    use waddling_errors::Role;

    generator.register_component(
        "Storage",
        Some("S3-compatible object storage. Handles file uploads, downloads, versioning, and presigned URL generation. Implements multipart uploads for large files, automatic retry, and integrity verification using checksums."),
        &[
            "Multipart upload for large files",
            "Presigned URL generation (GET/PUT)",
            "Object versioning and lifecycle",
            "Server-side encryption (SSE)",
            "Checksum verification (MD5/SHA256)",
            "Cross-region replication",
        ],
        &["Storage", "s3", "objects", "files", "upload", "cloud"]);

    // Register component locations with role-based visibility

    // PUBLIC: Examples for external users
    generator.register_component_location_with_role(
        "Storage",
        "examples/complete_system/components/storage.rs",
        Some(Role::Public),
    );
    generator.register_component_location_with_role(
        "Storage",
        "examples/storage_usage.rs",
        Some(Role::Public),
    );

    // DEVELOPER: Upload monitoring and debugging
    generator.register_component_location_with_role(
        "Storage",
        "src/storage/upload_monitor.rs",
        Some(Role::Developer),
    );
    generator.register_component_location_with_role(
        "Storage",
        "src/storage/debug_utils.rs",
        Some(Role::Developer),
    );

    // INTERNAL: Production implementation
    generator.register_component_location_with_role(
        "Storage",
        "src/storage/s3_client.rs",
        Some(Role::Internal),
    );
    generator.register_component_location_with_role(
        "Storage",
        "src/storage/upload_manager.rs",
        Some(Role::Internal),
    );
    generator.register_component_location_with_role(
        "Storage",
        "src/handlers/file_upload_handler.rs",
        Some(Role::Internal),
    );
    generator.register_component_location_with_role(
        "Storage",
        "src/storage/encryption_keys.rs",
        Some(Role::Internal),
    );
}

#[cfg(feature = "doc-gen")]
pub fn register_errors(generator: &mut waddling_errors::doc_generator::DocRegistry) {
    use waddling_errors::Role;

    let errors = vec![
        (
            "E.Storage.Permission.008",
            "S3 bucket access denied",
            &[
                "Check IAM permissions",
                "Verify bucket policy",
                "Update credentials",
            ][..],
            &["Storage", "s3", "permissions"][..],
            Role::Internal,
        ),
        (
            "C.Storage.Data.025",
            "CRITICAL: Object corruption detected",
            &["Retry upload", "Verify checksums", "Check network"],
            &["Storage", "integrity", "critical"],
            Role::Internal,
        ),
        (
            "E.Storage.Data.022",
            "Object already exists - upload conflict",
            &[
                "Use unique filename",
                "Enable versioning",
                "Check existing object",
            ],
            &["Storage", "conflict"],
            Role::Developer,
        ),
        (
            "E.Storage.Data.021",
            "Object not found in storage",
            &[
                "Verify object key",
                "Check bucket name",
                "Review deletion logs",
            ],
            &["Storage", "not-found"],
            Role::Public,
        ),
        (
            "K.Storage.Data.999",
            "Multipart upload completed successfully",
            &["Upload finished", "Object available"],
            &["Storage", "success"],
            Role::Public,
        ),
        (
            "T.Storage.Data.100",
            "Storage operation trace - debugging enabled",
            &["Debug trace active", "Check logs for details"],
            &["Storage", "debugging"],
            Role::Internal,
        ),
    ];

    for (code, desc, hints, tags, role) in &errors {
        let _ = generator.register(*code, *desc, hints, tags);

        let snippet = match role {
            Role::Internal => format!(
                "// Internal debugging\nlog::error!(\"[{}] {}\");",
                code, desc
            ),
            Role::Developer => format!(
                "// Developer API usage\nif let Err(e) = operation() {{\n    eprintln!(\"Error: {}\");\n}}",
                code
            ),
            Role::Public => format!(
                "// Public error handling\nmatch result {{\n    Err(_) => println!(\"Operation failed: {}\"),\n    Ok(_) => println!(\"Success\"),\n}}",
                desc
            ),
        };

        generator.add_snippet_for_role(
            format!("{:?} - Usage Example", role),
            "rust",
            snippet,
            *role,
        );
    }
}

// ============================================================================
// Demo Functions
// ============================================================================

pub fn demo() {
    println!("☁️  STORAGE Component Errors:\n");
    println!("  {} - Permission denied", ERR_PERMISSION_DENIED.code());
    println!("  {} - Data corrupted", CRIT_DATA_CORRUPTED.code());
    println!("  {} - Already exists", ERR_DATA_ALREADYEXISTS.code());
    println!("  {} - Not found", ERR_DATA_NOTFOUND.code());
    println!("  {} - Upload complete", COMPLETE_UPLOAD.code());
    println!("  {} - Trace operation", TRACE_OPERATION.code());
}