unity_asset_binary/metadata/
mod.rs

1//! Unity asset metadata processing module
2//!
3//! This module provides comprehensive metadata extraction and analysis capabilities
4//! for Unity assets, organized following best practices for maintainability.
5//!
6//! # Architecture
7//!
8//! The module is organized into several sub-modules:
9//! - `types` - Core data structures for metadata representation
10//! - `extractor` - Main metadata extraction functionality
11//! - `analyzer` - Advanced dependency and relationship analysis
12//!
13//! # Examples
14//!
15//! ```rust,no_run
16//! use unity_asset_binary::metadata::{MetadataExtractor, ExtractionConfig};
17//! use unity_asset_binary::asset::{SerializedFile, SerializedFileHeader};
18//!
19//! // Create extractor with custom configuration
20//! let config = ExtractionConfig {
21//!     include_dependencies: true,
22//!     include_hierarchy: true,
23//!     max_objects: Some(1000),
24//!     include_performance: true,
25//!     include_object_details: true,
26//! };
27//! let extractor = MetadataExtractor::with_config(config);
28//!
29//! // Note: In real usage, you would load a SerializedFile from actual data
30//! // For demonstration, we'll just show the extractor creation
31//! println!("Extractor created with config");
32//! println!("Metadata extracted successfully");
33//! # Ok::<(), unity_asset_binary::error::BinaryError>(())
34//! ```
35
36pub mod analyzer;
37pub mod extractor;
38pub mod types;
39
40// Re-export main types for easy access
41pub use analyzer::{DependencyAnalyzer, RelationshipAnalyzer};
42pub use extractor::MetadataExtractor;
43pub use types::{
44    // Core metadata types
45    AssetMetadata,
46    AssetReference,
47    // Relationship types
48    AssetRelationships,
49    ComponentRelationship,
50    DependencyGraph,
51    // Dependency types
52    DependencyInfo,
53    ExternalReference,
54    ExtractionConfig,
55    ExtractionResult,
56    ExtractionStats,
57    FileInfo,
58    GameObjectHierarchy,
59    InternalReference,
60    MemoryUsage,
61    ObjectStatistics,
62    ObjectSummary,
63    // Performance and configuration
64    PerformanceMetrics,
65    // Constants
66    class_ids,
67};
68
69/// Main metadata processing facade
70///
71/// This struct provides a high-level interface for metadata processing,
72/// combining extraction and analysis functionality.
73pub struct MetadataProcessor {
74    extractor: MetadataExtractor,
75    dependency_analyzer: Option<DependencyAnalyzer>,
76    relationship_analyzer: Option<RelationshipAnalyzer>,
77}
78
79impl MetadataProcessor {
80    /// Create a new metadata processor with default settings
81    pub fn new() -> Self {
82        Self {
83            extractor: MetadataExtractor::new(),
84            dependency_analyzer: None,
85            relationship_analyzer: None,
86        }
87    }
88
89    /// Create a metadata processor with custom configuration
90    pub fn with_config(config: ExtractionConfig) -> Self {
91        let enable_advanced = config.include_dependencies || config.include_hierarchy;
92
93        Self {
94            extractor: MetadataExtractor::with_config(config),
95            dependency_analyzer: if enable_advanced {
96                Some(DependencyAnalyzer::new())
97            } else {
98                None
99            },
100            relationship_analyzer: if enable_advanced {
101                Some(RelationshipAnalyzer::new())
102            } else {
103                None
104            },
105        }
106    }
107
108    /// Process metadata from a SerializedFile
109    pub fn process_asset(
110        &mut self,
111        asset: &crate::SerializedFile,
112    ) -> crate::error::Result<ExtractionResult> {
113        let mut result = self.extractor.extract_from_asset(asset)?;
114
115        // Enhanced dependency analysis if analyzer is available
116        if let Some(ref mut analyzer) = self.dependency_analyzer
117            && self.extractor.config().include_dependencies
118        {
119            let objects: Vec<&crate::asset::ObjectInfo> = asset.objects.iter().collect();
120            match analyzer.analyze_dependencies(&objects) {
121                Ok(deps) => {
122                    result.metadata.dependencies = deps;
123                }
124                Err(e) => {
125                    result.add_warning(format!("Enhanced dependency analysis failed: {}", e));
126                }
127            }
128        }
129
130        // Enhanced relationship analysis if analyzer is available
131        if let Some(ref mut analyzer) = self.relationship_analyzer
132            && self.extractor.config().include_hierarchy
133        {
134            let objects: Vec<&crate::asset::ObjectInfo> = asset.objects.iter().collect();
135            match analyzer.analyze_relationships(&objects) {
136                Ok(rels) => {
137                    result.metadata.relationships = rels;
138                }
139                Err(e) => {
140                    result.add_warning(format!("Enhanced relationship analysis failed: {}", e));
141                }
142            }
143        }
144
145        Ok(result)
146    }
147
148    /// Process metadata from an AssetBundle
149    pub fn process_bundle(
150        &mut self,
151        bundle: &crate::AssetBundle,
152    ) -> crate::error::Result<Vec<ExtractionResult>> {
153        let mut results = Vec::new();
154
155        for asset in &bundle.assets {
156            let result = self.process_asset(asset)?;
157            results.push(result);
158        }
159
160        Ok(results)
161    }
162
163    /// Get the current extraction configuration
164    pub fn config(&self) -> &ExtractionConfig {
165        self.extractor.config()
166    }
167
168    /// Update the extraction configuration
169    pub fn set_config(&mut self, config: ExtractionConfig) {
170        let enable_advanced = config.include_dependencies || config.include_hierarchy;
171
172        self.extractor.set_config(config);
173
174        // Initialize analyzers if needed
175        if enable_advanced {
176            if self.dependency_analyzer.is_none() {
177                self.dependency_analyzer = Some(DependencyAnalyzer::new());
178            }
179            if self.relationship_analyzer.is_none() {
180                self.relationship_analyzer = Some(RelationshipAnalyzer::new());
181            }
182        }
183    }
184
185    /// Clear internal caches
186    pub fn clear_caches(&mut self) {
187        if let Some(ref mut analyzer) = self.dependency_analyzer {
188            analyzer.clear_cache();
189        }
190        if let Some(ref mut analyzer) = self.relationship_analyzer {
191            analyzer.clear_cache();
192        }
193    }
194
195    /// Check if advanced analysis is enabled
196    pub fn has_advanced_analysis(&self) -> bool {
197        self.dependency_analyzer.is_some() || self.relationship_analyzer.is_some()
198    }
199}
200
201impl Default for MetadataProcessor {
202    fn default() -> Self {
203        Self::new()
204    }
205}
206
207/// Convenience functions for common operations
208/// Create a metadata processor with default settings
209pub fn create_processor() -> MetadataProcessor {
210    MetadataProcessor::default()
211}
212
213/// Create a metadata processor with performance-focused configuration
214pub fn create_performance_processor() -> MetadataProcessor {
215    let config = ExtractionConfig {
216        include_dependencies: false,
217        include_hierarchy: false,
218        max_objects: Some(1000),
219        include_performance: true,
220        include_object_details: false,
221    };
222    MetadataProcessor::with_config(config)
223}
224
225/// Create a metadata processor with comprehensive analysis
226pub fn create_comprehensive_processor() -> MetadataProcessor {
227    let config = ExtractionConfig {
228        include_dependencies: true,
229        include_hierarchy: true,
230        max_objects: None,
231        include_performance: true,
232        include_object_details: true,
233    };
234    MetadataProcessor::with_config(config)
235}
236
237/// Extract basic metadata from an asset
238pub fn extract_basic_metadata(
239    asset: &crate::SerializedFile,
240) -> crate::error::Result<AssetMetadata> {
241    let extractor = MetadataExtractor::new();
242    let result = extractor.extract_from_asset(asset)?;
243    Ok(result.metadata)
244}
245
246/// Extract metadata with custom configuration
247pub fn extract_metadata_with_config(
248    asset: &crate::SerializedFile,
249    config: ExtractionConfig,
250) -> crate::error::Result<ExtractionResult> {
251    let extractor = MetadataExtractor::with_config(config);
252    extractor.extract_from_asset(asset)
253}
254
255/// Get quick statistics for an asset
256pub fn get_asset_statistics(asset: &crate::SerializedFile) -> AssetStatistics {
257    AssetStatistics {
258        object_count: asset.objects.len(),
259        type_count: asset.types.len(),
260        external_count: asset.externals.len(),
261        file_size: asset.header.file_size as u64,
262        unity_version: asset.unity_version.clone(),
263        format_version: asset.header.version,
264    }
265}
266
267/// Quick asset statistics
268#[derive(Debug, Clone)]
269pub struct AssetStatistics {
270    pub object_count: usize,
271    pub type_count: usize,
272    pub external_count: usize,
273    pub file_size: u64,
274    pub unity_version: String,
275    pub format_version: u32,
276}
277
278/// Metadata processing options
279#[derive(Debug, Clone)]
280pub struct ProcessingOptions {
281    pub enable_caching: bool,
282    pub max_cache_size: usize,
283    pub parallel_processing: bool,
284    pub memory_limit_mb: Option<usize>,
285}
286
287impl Default for ProcessingOptions {
288    fn default() -> Self {
289        Self {
290            enable_caching: true,
291            max_cache_size: 1000,
292            parallel_processing: false,
293            memory_limit_mb: None,
294        }
295    }
296}
297
298/// Check if metadata extraction is supported for an asset
299pub fn is_extraction_supported(asset: &crate::SerializedFile) -> bool {
300    // Support Unity 5.0+ (version 10+)
301    asset.header.version >= 10
302}
303
304/// Get recommended extraction configuration for an asset
305pub fn get_recommended_config(asset: &crate::SerializedFile) -> ExtractionConfig {
306    let object_count = asset.objects.len();
307
308    if object_count > 10000 {
309        // Large asset - performance focused
310        ExtractionConfig {
311            include_dependencies: false,
312            include_hierarchy: false,
313            max_objects: Some(5000),
314            include_performance: true,
315            include_object_details: false,
316        }
317    } else if object_count > 1000 {
318        // Medium asset - balanced
319        ExtractionConfig {
320            include_dependencies: true,
321            include_hierarchy: false,
322            max_objects: Some(2000),
323            include_performance: true,
324            include_object_details: true,
325        }
326    } else {
327        // Small asset - comprehensive
328        ExtractionConfig::default()
329    }
330}
331
332#[cfg(test)]
333mod tests {
334    use super::*;
335
336    #[test]
337    fn test_processor_creation() {
338        let processor = create_processor();
339        assert!(!processor.has_advanced_analysis());
340    }
341
342    #[test]
343    fn test_comprehensive_processor() {
344        let processor = create_comprehensive_processor();
345        assert!(processor.has_advanced_analysis());
346        assert!(processor.config().include_dependencies);
347        assert!(processor.config().include_hierarchy);
348    }
349
350    #[test]
351    fn test_performance_processor() {
352        let processor = create_performance_processor();
353        assert!(!processor.config().include_dependencies);
354        assert!(!processor.config().include_hierarchy);
355        assert_eq!(processor.config().max_objects, Some(1000));
356    }
357
358    #[test]
359    fn test_extraction_support() {
360        // This would need a mock SerializedFile for proper testing
361        // For now, just test that the function exists
362    }
363}