pub mod bim;
pub mod error;
pub mod greenhouse;
pub mod labels;
pub mod spectral;
pub mod tm30;
pub mod types;
pub mod validate;
#[cfg(feature = "xml")]
pub mod xml;
#[cfg(feature = "xml")]
pub mod spdx;
#[cfg(feature = "json")]
pub mod json;
#[cfg(feature = "xml")]
pub mod oxl;
pub mod convert;
pub use bim::{
BimParameters, ElectricalPhase, EmergencyType, HousingShape, LedDriveType, MountingType,
VoltageType,
};
pub use error::{AtlaError, Result};
pub use greenhouse::{GreenhouseDiagram, GreenhouseLabels, GreenhouseTheme};
pub use labels::SpectralLabels;
pub use spectral::{
synthesize_spectrum, SpectralDiagram, SpectralMetrics, SpectralSvgLabels, SpectralTheme,
};
pub use tm30::{calculate_tm30, Tm30Result, Tm30Theme};
pub use types::*;
pub use validate::{
validate, validate_with_schema, ValidationMessage, ValidationResult, ValidationSchema,
};
pub fn detect_schema_version(content: &str) -> SchemaVersion {
let trimmed = content.trim();
if trimmed.contains("<IESTM33-22") || trimmed.contains("<IESTM33-22>") {
return SchemaVersion::Tm3323;
}
if trimmed.contains("<LuminaireOpticalData") {
return SchemaVersion::AtlaS001;
}
SchemaVersion::AtlaS001
}
pub fn parse(content: &str) -> Result<LuminaireOpticalData> {
let trimmed = content.trim();
if trimmed.starts_with('{') {
#[cfg(feature = "json")]
{
json::parse(content)
}
#[cfg(not(feature = "json"))]
{
Err(AtlaError::JsonParse(
"JSON support not enabled. Enable the 'json' feature.".to_string(),
))
}
} else if trimmed.starts_with('<') {
#[cfg(feature = "xml")]
{
xml::parse(content)
}
#[cfg(not(feature = "xml"))]
{
Err(AtlaError::XmlParse(
"XML support not enabled. Enable the 'xml' feature.".to_string(),
))
}
} else {
Err(AtlaError::XmlParse(
"Unknown format: content must start with '<' (XML) or '{' (JSON)".to_string(),
))
}
}
pub fn parse_file(path: impl AsRef<std::path::Path>) -> Result<LuminaireOpticalData> {
let path = path.as_ref();
let content = std::fs::read_to_string(path)?;
if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
match ext.to_lowercase().as_str() {
"json" => {
#[cfg(feature = "json")]
return json::parse(&content);
#[cfg(not(feature = "json"))]
return Err(AtlaError::JsonParse(
"JSON support not enabled. Enable the 'json' feature.".to_string(),
));
}
"xml" => {
#[cfg(feature = "xml")]
return xml::parse(&content);
#[cfg(not(feature = "xml"))]
return Err(AtlaError::XmlParse(
"XML support not enabled. Enable the 'xml' feature.".to_string(),
));
}
"oxl" | "oxc" => {
#[cfg(feature = "xml")]
{
let pkg = oxl::parse(&content)?;
return pkg.luminaires.into_iter().next().ok_or_else(|| {
AtlaError::XmlParse(
"OXL/OXC file contains no luminaires (commercial-only?). \
Use oxl::parse for catalog-level metadata."
.into(),
)
});
}
#[cfg(not(feature = "xml"))]
return Err(AtlaError::XmlParse(
"XML support not enabled. Enable the 'xml' feature.".to_string(),
));
}
_ => {}
}
}
parse(&content)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_auto_detect_xml() {
let xml = r#"<?xml version="1.0"?>
<LuminaireOpticalData version="1.0">
<Header><Manufacturer>Test</Manufacturer></Header>
<Emitter><Quantity>1</Quantity></Emitter>
</LuminaireOpticalData>"#;
let doc = parse(xml).unwrap();
assert_eq!(doc.header.manufacturer, Some("Test".to_string()));
}
#[cfg(feature = "json")]
#[test]
fn test_auto_detect_json() {
let json =
r#"{"version":"1.0","header":{"manufacturer":"Test"},"emitters":[{"quantity":1}]}"#;
let doc = parse(json).unwrap();
assert_eq!(doc.header.manufacturer, Some("Test".to_string()));
}
}