style: apply rustfmt to entire codebase

- Fix all formatting issues for CI compliance
- Consistent code style across all files
- Proper struct/enum formatting
- Fixed import ordering
This commit is contained in:
Stefano Amorelli
2025-08-17 13:41:00 +03:00
parent 3fd81d83a1
commit 3c1519e405
10 changed files with 196 additions and 144 deletions

View File

@@ -1,5 +1,5 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use crabrl::Parser; use crabrl::Parser;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn parse_small_file(c: &mut Criterion) { fn parse_small_file(c: &mut Criterion) {
let parser = Parser::new(); let parser = Parser::new();
@@ -21,4 +21,3 @@ fn parse_medium_file(c: &mut Criterion) {
criterion_group!(benches, parse_small_file, parse_medium_file); criterion_group!(benches, parse_small_file, parse_medium_file);
criterion_main!(benches); criterion_main!(benches);

View File

@@ -34,4 +34,3 @@ fn main() {
} }
} }
} }

View File

@@ -20,4 +20,3 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(()) Ok(())
} }

View File

@@ -27,4 +27,3 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(()) Ok(())
} }

View File

@@ -17,11 +17,13 @@ fn main() {
Ok(doc) => { Ok(doc) => {
let elapsed = start.elapsed(); let elapsed = start.elapsed();
let ms = elapsed.as_secs_f64() * 1000.0; let ms = elapsed.as_secs_f64() * 1000.0;
println!("crabrl found: {} facts, {} contexts, {} units (in {:.3}ms)", println!(
"crabrl found: {} facts, {} contexts, {} units (in {:.3}ms)",
doc.facts.len(), doc.facts.len(),
doc.contexts.len(), doc.contexts.len(),
doc.units.len(), doc.units.len(),
ms); ms
);
// Additional stats // Additional stats
println!("Facts: {}", doc.facts.len()); println!("Facts: {}", doc.facts.len());
@@ -37,5 +39,3 @@ fn main() {
} }
} }
} }

View File

@@ -10,7 +10,7 @@ pub mod validator;
pub use simple_parser::Parser; pub use simple_parser::Parser;
// Re-export main types // Re-export main types
pub use model::{Document, Fact, Context, Unit}; pub use model::{Context, Document, Fact, Unit};
// Create validator wrapper for the CLI // Create validator wrapper for the CLI
pub struct Validator { pub struct Validator {

View File

@@ -6,7 +6,7 @@ use colored::*;
use std::path::PathBuf; use std::path::PathBuf;
use std::time::Instant; use std::time::Instant;
use crabrl::{Parser, Validator, ValidationConfig}; use crabrl::{Parser, ValidationConfig, Validator};
/// High-performance XBRL parser and validator /// High-performance XBRL parser and validator
#[derive(ClapParser)] #[derive(ClapParser)]
@@ -62,10 +62,15 @@ fn main() -> Result<()> {
let cli = Cli::parse(); let cli = Cli::parse();
match cli.command { match cli.command {
Commands::Parse { input, json: _, stats } => { Commands::Parse {
input,
json: _,
stats,
} => {
let start = Instant::now(); let start = Instant::now();
let parser = Parser::new(); let parser = Parser::new();
let doc = parser.parse_file(&input) let doc = parser
.parse_file(&input)
.with_context(|| format!("Failed to parse {}", input.display()))?; .with_context(|| format!("Failed to parse {}", input.display()))?;
let elapsed = start.elapsed(); let elapsed = start.elapsed();
@@ -76,14 +81,21 @@ fn main() -> Result<()> {
if stats { if stats {
println!(" Time: {:.2}ms", elapsed.as_secs_f64() * 1000.0); println!(" Time: {:.2}ms", elapsed.as_secs_f64() * 1000.0);
println!(" Throughput: {:.0} facts/sec", println!(
doc.facts.len() as f64 / elapsed.as_secs_f64()); " Throughput: {:.0} facts/sec",
doc.facts.len() as f64 / elapsed.as_secs_f64()
);
} }
} }
Commands::Validate { input, profile, strict } => { Commands::Validate {
input,
profile,
strict,
} => {
let parser = Parser::new(); let parser = Parser::new();
let doc = parser.parse_file(&input) let doc = parser
.parse_file(&input)
.with_context(|| format!("Failed to parse {}", input.display()))?; .with_context(|| format!("Failed to parse {}", input.display()))?;
let config = match profile.as_str() { let config = match profile.as_str() {
@@ -95,9 +107,17 @@ fn main() -> Result<()> {
let result = validator.validate(&doc)?; let result = validator.validate(&doc)?;
if result.is_valid { if result.is_valid {
println!("{} {} - Document is valid", "".green().bold(), input.display()); println!(
"{} {} - Document is valid",
"".green().bold(),
input.display()
);
} else { } else {
println!("{} {} - Validation failed", "".red().bold(), input.display()); println!(
"{} {} - Validation failed",
"".red().bold(),
input.display()
);
println!(" Errors: {}", result.errors.len()); println!(" Errors: {}", result.errors.len());
println!(" Warnings: {}", result.warnings.len()); println!(" Warnings: {}", result.warnings.len());
@@ -150,8 +170,10 @@ fn main() -> Result<()> {
println!(" Median: {:.3}ms", median.as_secs_f64() * 1000.0); println!(" Median: {:.3}ms", median.as_secs_f64() * 1000.0);
println!(" Mean: {:.3}ms", mean.as_secs_f64() * 1000.0); println!(" Mean: {:.3}ms", mean.as_secs_f64() * 1000.0);
println!(" Max: {:.3}ms", max.as_secs_f64() * 1000.0); println!(" Max: {:.3}ms", max.as_secs_f64() * 1000.0);
println!(" Throughput: {:.0} facts/sec", println!(
doc_facts as f64 / mean.as_secs_f64()); " Throughput: {:.0} facts/sec",
doc_facts as f64 / mean.as_secs_f64()
);
} }
} }

View File

@@ -5,7 +5,6 @@ use std::collections::HashMap;
// Core XBRL Data Structures - Full Specification Support // Core XBRL Data Structures - Full Specification Support
// ============================================================================ // ============================================================================
#[repr(C, align(64))] #[repr(C, align(64))]
#[derive(Clone)] #[derive(Clone)]
pub struct FactStorage { pub struct FactStorage {
@@ -111,8 +110,13 @@ pub struct Scenario {
// Period with forever support // Period with forever support
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Period { pub enum Period {
Instant { date: CompactString }, Instant {
Duration { start: CompactString, end: CompactString }, date: CompactString,
},
Duration {
start: CompactString,
end: CompactString,
},
Forever, Forever,
} }
@@ -347,6 +351,3 @@ impl Document {
} }
} }
} }

View File

@@ -26,17 +26,16 @@ impl Parser {
let text = String::from_utf8_lossy(data); let text = String::from_utf8_lossy(data);
// Count facts (very simplified) // Count facts (very simplified)
let fact_count = text.matches("<us-gaap:").count() + let fact_count = text.matches("<us-gaap:").count()
text.matches("<dei:").count() + + text.matches("<dei:").count()
text.matches("<ifrs:").count(); + text.matches("<ifrs:").count();
// Count contexts // Count contexts
let context_count = text.matches("<context ").count() + let context_count =
text.matches("<xbrli:context").count(); text.matches("<context ").count() + text.matches("<xbrli:context").count();
// Count units // Count units
let unit_count = text.matches("<unit ").count() + let unit_count = text.matches("<unit ").count() + text.matches("<xbrli:unit").count();
text.matches("<xbrli:unit").count();
// Create dummy document with approximate counts // Create dummy document with approximate counts
let mut doc = Document { let mut doc = Document {

View File

@@ -1,15 +1,33 @@
// Comprehensive XBRL validation // Comprehensive XBRL validation
use crate::{model::*, Result, Error}; use crate::{model::*, Error, Result};
use std::collections::HashSet; use std::collections::HashSet;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ValidationError { pub enum ValidationError {
InvalidContextRef { fact_index: usize, context_id: u16 }, InvalidContextRef {
InvalidUnitRef { fact_index: usize, unit_id: u16 }, fact_index: usize,
CalculationInconsistency { concept: String, expected: f64, actual: f64 }, context_id: u16,
InvalidDataType { concept: String, expected_type: String, actual_value: String }, },
MissingRequiredElement { element: String }, InvalidUnitRef {
DuplicateId { id: String }, fact_index: usize,
unit_id: u16,
},
CalculationInconsistency {
concept: String,
expected: f64,
actual: f64,
},
InvalidDataType {
concept: String,
expected_type: String,
actual_value: String,
},
MissingRequiredElement {
element: String,
},
DuplicateId {
id: String,
},
} }
pub struct XbrlValidator { pub struct XbrlValidator {
@@ -137,7 +155,10 @@ impl XbrlValidator {
}); });
} }
} }
UnitType::Divide { numerator, denominator } => { UnitType::Divide {
numerator,
denominator,
} => {
if numerator.is_empty() || denominator.is_empty() { if numerator.is_empty() || denominator.is_empty() {
errors.push(ValidationError::MissingRequiredElement { errors.push(ValidationError::MissingRequiredElement {
element: format!("Numerator/denominator for unit {}", unit.id), element: format!("Numerator/denominator for unit {}", unit.id),
@@ -229,7 +250,7 @@ impl ValidationContext {
pub fn add_rule<F>(&mut self, rule: F) pub fn add_rule<F>(&mut self, rule: F)
where where
F: Fn(&Document) -> Vec<ValidationError> + 'static F: Fn(&Document) -> Vec<ValidationError> + 'static,
{ {
self.custom_rules.push(Box::new(rule)); self.custom_rules.push(Box::new(rule));
} }
@@ -268,8 +289,10 @@ pub fn sec_validation_rules(doc: &Document) -> Vec<ValidationError> {
for ctx in &doc.contexts { for ctx in &doc.contexts {
// Check for current period context // Check for current period context
if ctx.id.contains("CurrentYear") || ctx.id.contains("CurrentPeriod") || if ctx.id.contains("CurrentYear")
ctx.id.contains("DocumentPeriodEndDate") { || ctx.id.contains("CurrentPeriod")
|| ctx.id.contains("DocumentPeriodEndDate")
{
has_current_period = true; has_current_period = true;
} }
@@ -291,8 +314,10 @@ pub fn sec_validation_rules(doc: &Document) -> Vec<ValidationError> {
for i in 0..doc.facts.concept_ids.len() { for i in 0..doc.facts.concept_ids.len() {
if i < doc.concept_names.len() { if i < doc.concept_names.len() {
let concept = &doc.concept_names[i]; let concept = &doc.concept_names[i];
if concept.contains("dei:") || concept.contains("DocumentType") || if concept.contains("dei:")
concept.contains("EntityRegistrantName") { || concept.contains("DocumentType")
|| concept.contains("EntityRegistrantName")
{
has_dei_elements = true; has_dei_elements = true;
} }
} }
@@ -390,8 +415,10 @@ pub fn ifrs_validation_rules(doc: &Document) -> Vec<ValidationError> {
Period::Duration { start, end: _ } => { Period::Duration { start, end: _ } => {
has_reporting_period = true; has_reporting_period = true;
// IFRS requires comparative information // IFRS requires comparative information
if start.contains("PY") || ctx.id.contains("PriorYear") || if start.contains("PY")
ctx.id.contains("Comparative") { || ctx.id.contains("PriorYear")
|| ctx.id.contains("Comparative")
{
has_comparative_period = true; has_comparative_period = true;
} }
} }
@@ -436,7 +463,8 @@ pub fn ifrs_validation_rules(doc: &Document) -> Vec<ValidationError> {
for member in &segment.explicit_members { for member in &segment.explicit_members {
// IFRS dimensions should follow specific patterns // IFRS dimensions should follow specific patterns
if !member.dimension.contains(":") { if !member.dimension.contains(":") {
dimension_validations.push(format!("Invalid dimension format: {}", member.dimension)); dimension_validations
.push(format!("Invalid dimension format: {}", member.dimension));
} }
if member.dimension.contains("ifrs") || member.dimension.contains("ifrs-full") { if member.dimension.contains("ifrs") || member.dimension.contains("ifrs-full") {
// Valid IFRS dimension // Valid IFRS dimension
@@ -486,13 +514,19 @@ pub fn ifrs_validation_rules(doc: &Document) -> Vec<ValidationError> {
let concept = &doc.concept_names[i]; let concept = &doc.concept_names[i];
let lower = concept.to_lowercase(); let lower = concept.to_lowercase();
if lower.contains("financialposition") || lower.contains("balancesheet") || if lower.contains("financialposition")
lower.contains("assets") || lower.contains("liabilities") { || lower.contains("balancesheet")
|| lower.contains("assets")
|| lower.contains("liabilities")
{
has_financial_position = true; has_financial_position = true;
} }
if lower.contains("comprehensiveincome") || lower.contains("profitorloss") || if lower.contains("comprehensiveincome")
lower.contains("income") || lower.contains("revenue") { || lower.contains("profitorloss")
|| lower.contains("income")
|| lower.contains("revenue")
{
has_comprehensive_income = true; has_comprehensive_income = true;
} }