ycbust 0.5.0

Library and CLI tool for downloading and extracting the YCB Object and Model Set for 3D rendering and simulation
Documentation
// Copyright 2025 Agentic-Insights
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0

//! Typed error type for all `ycbust` public APIs.

use thiserror::Error;

/// Errors returned by the `ycbust` public API.
///
/// Marked `#[non_exhaustive]` so adding new variants is not a breaking change.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum YcbError {
    /// A network request failed (DNS, TLS, connection, body read).
    #[error("network error: {0}")]
    Network(#[from] reqwest::Error),

    /// An HTTP response returned a non-success status.
    #[error("http {status} for {url}")]
    HttpStatus {
        /// HTTP status code returned by the server.
        status: u16,
        /// URL that returned the status.
        url: String,
    },

    /// Tar / gzip extraction failed.
    #[error("extraction failed for {path}: {source}")]
    Extraction {
        /// Path of the archive that failed to extract.
        path: String,
        /// Underlying I/O error from the tar/gzip layer.
        #[source]
        source: std::io::Error,
    },

    /// A filesystem operation failed.
    #[error("io error: {0}")]
    Io(#[from] std::io::Error),

    /// JSON deserialization failed (e.g. parsing the YCB object index).
    #[error("invalid response: {0}")]
    InvalidResponse(String),

    /// An archive entry attempted a path traversal (contained `..` or
    /// canonicalized outside the output directory).
    #[error("unsafe archive entry: {0}")]
    UnsafeArchive(String),
}

/// Convenience alias for `Result<T, YcbError>`.
pub type Result<T> = std::result::Result<T, YcbError>;

impl YcbError {
    pub(crate) fn extraction(path: impl Into<String>, source: std::io::Error) -> Self {
        YcbError::Extraction {
            path: path.into(),
            source,
        }
    }
}