Skip to main content

cdx_core/asset/
mod.rs

1//! Asset management for embedded images, fonts, and files.
2//!
3//! This module provides types and utilities for managing assets embedded
4//! within Codex documents.
5//!
6//! # Asset Types
7//!
8//! - **Images**: AVIF, WebP, PNG, JPEG, SVG formats with dimensions and alt text
9//! - **Fonts**: WOFF2, WOFF, TTF, OTF formats with font family metadata
10//! - **Embeds**: Arbitrary files with MIME type and description
11//!
12//! # Asset Index
13//!
14//! Each asset category has an index file (e.g., `assets/images/index.json`)
15//! that lists all assets with their metadata and hashes for verification.
16//!
17//! # Example
18//!
19//! ```rust,ignore
20//! use cdx_core::asset::{ImageAsset, ImageFormat};
21//!
22//! let image = ImageAsset::new("logo", ImageFormat::Png)
23//!     .with_dimensions(200, 100)
24//!     .with_alt("Company logo");
25//! ```
26
27mod font;
28mod image;
29mod index;
30
31pub use font::{FontAsset, FontFormat, FontStyle, FontWeight};
32pub use image::{ImageAsset, ImageFormat, ImageVariant};
33pub use index::{
34    AssetAlias, AssetEntry, AssetIndex, EmbedAsset, EmbedIndex, FontIndex, ImageIndex,
35};
36
37use crate::{DocumentId, Result};
38
39/// Common trait for all asset types.
40pub trait Asset {
41    /// Get the asset's unique identifier.
42    fn id(&self) -> &str;
43
44    /// Get the path to the asset file within the archive.
45    fn path(&self) -> &str;
46
47    /// Get the content hash of the asset.
48    fn hash(&self) -> &DocumentId;
49
50    /// Get the size in bytes.
51    fn size(&self) -> u64;
52
53    /// Get the MIME type.
54    fn mime_type(&self) -> &str;
55}
56
57/// Verify an asset's integrity by checking its hash.
58///
59/// # Errors
60///
61/// Returns an error if the hash does not match the expected value.
62pub fn verify_asset_hash(
63    path: &str,
64    data: &[u8],
65    expected: &DocumentId,
66    algorithm: crate::HashAlgorithm,
67) -> Result<()> {
68    let actual = crate::Hasher::hash(algorithm, data);
69    if actual.hex_digest() != expected.hex_digest() {
70        return Err(crate::Error::HashMismatch {
71            path: path.to_string(),
72            expected: expected.hex_digest(),
73            actual: actual.hex_digest(),
74        });
75    }
76    Ok(())
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use crate::HashAlgorithm;
83
84    #[test]
85    fn test_verify_asset_hash_valid() {
86        let data = b"test asset data";
87        let hash = crate::Hasher::hash(HashAlgorithm::Sha256, data);
88        assert!(verify_asset_hash("test.png", data, &hash, HashAlgorithm::Sha256).is_ok());
89    }
90
91    #[test]
92    fn test_verify_asset_hash_invalid() {
93        let data = b"test asset data";
94        let wrong_hash = crate::Hasher::hash(HashAlgorithm::Sha256, b"different data");
95        assert!(verify_asset_hash("test.png", data, &wrong_hash, HashAlgorithm::Sha256).is_err());
96    }
97}