Skip to content

Commit

Permalink
Streamline the process of JSON/XML parsing via traits.
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrej33 committed Sep 3, 2024
1 parent 68ea5e1 commit 8ba2160
Show file tree
Hide file tree
Showing 8 changed files with 280 additions and 217 deletions.
221 changes: 221 additions & 0 deletions src/_impl_bma_model.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
use crate::bma_model::*;
use crate::enums::VariableType;
use crate::json_model::JsonBmaModel;
use crate::traits::{JsonSerde, XmlSerde};
use crate::xml_model::XmlBmaModel;
use std::collections::HashMap;

impl<'de> JsonSerde<'de> for BmaModel {
fn to_json_str(&self) -> String {
todo!()
}

fn to_pretty_json_str(&self) -> String {
todo!()
}

fn from_json_str(json_str: &'de str) -> Result<Self, String> {
let json_model: JsonBmaModel = serde_json::from_str(json_str).map_err(|e| e.to_string())?;
let model = BmaModel::from(json_model);
Ok(model)
}
}

impl<'de> XmlSerde<'de> for BmaModel {
fn to_xml_str(&self) -> String {
todo!()
}

fn to_pretty_xml_str(&self) -> String {
todo!()
}

fn from_xml_str(xml_str: &'de str) -> Result<Self, String> {
let xml_model: XmlBmaModel = serde_xml_rs::from_str(xml_str).map_err(|e| e.to_string())?;
let model = BmaModel::from(xml_model);
Ok(model)
}
}

impl From<JsonBmaModel> for BmaModel {
fn from(json_model: JsonBmaModel) -> Self {
// Create a mapping from variable IDs to their names from the layout
let layout_var_names: HashMap<u32, String> = json_model
.layout
.as_ref()
.map(|layout| {
layout
.variables
.iter()
.filter(|layout_var| layout_var.name.is_some())
.map(|layout_var| (layout_var.id, layout_var.name.clone().unwrap()))
.collect()
})
.unwrap_or_default();

// Convert the model
let model = Model {
name: json_model.model.name,
variables: json_model
.model
.variables
.into_iter()
.map(|var| Variable {
id: var.id,
name: var
.name
.unwrap_or(layout_var_names.get(&var.id).cloned().unwrap_or_default()), // Use the name from layout
variable_type: json_model
.layout
.as_ref()
.and_then(|layout| layout.variables.iter().find(|v| v.id == var.id))
.map(|v| v.r#type)
.unwrap_or(VariableType::Default), // Use the type from layout if available
range_from: var.range_from,
range_to: var.range_to,
formula: var.formula,
})
.collect(),
relationships: json_model
.model
.relationships
.into_iter()
.map(|rel| Relationship {
id: rel.id,
from_variable: rel.from_variable,
to_variable: rel.to_variable,
relationship_type: rel.r#type,
})
.collect(),
};

// Convert the layout
let layout = json_model
.layout
.map(|layout| Layout {
variables: layout
.variables
.into_iter()
.map(|var| LayoutVariable {
id: var.id,
container_id: var.container_id,
position_x: var.position_x,
position_y: var.position_y,
cell_x: var.cell_x,
cell_y: var.cell_y,
angle: var.angle,
})
.collect(),
containers: layout
.containers
.into_iter()
.map(|container| Container {
id: container.id,
name: container.name,
size: container.size,
position_x: container.position_x,
position_y: container.position_y,
})
.collect(),
zoom_level: None,
pan_x: None,
pan_y: None,
})
.unwrap_or_else(|| Layout {
variables: vec![],
containers: vec![],
zoom_level: None,
pan_x: None,
pan_y: None,
});

// metadata not present in JsonBmaModel
let metadata = HashMap::new();

BmaModel {
model,
layout,
metadata,
}
}
}

impl From<XmlBmaModel> for BmaModel {
fn from(xml_model: XmlBmaModel) -> Self {
// Convert the model
let model = Model {
name: xml_model.name,
variables: xml_model
.variables
.variable
.clone()
.into_iter()
.map(|var| Variable {
id: var.id,
name: var.name,
variable_type: var.r#type,
range_from: var.range_from,
range_to: var.range_to,
formula: var.formula,
})
.collect(),
relationships: xml_model
.relationships
.relationship
.into_iter()
.map(|rel| Relationship {
id: rel.id,
from_variable: rel.from_variable_id,
to_variable: rel.to_variable_id,
relationship_type: rel.r#type,
})
.collect(),
};

// Convert the layout
let layout = Layout {
variables: xml_model
.variables
.variable
.into_iter()
.map(|var| LayoutVariable {
id: var.id,
container_id: var.container_id,
position_x: var.position_x,
position_y: var.position_y,
cell_x: Some(var.cell_x),
cell_y: Some(var.cell_y),
angle: var.angle,
})
.collect(),
containers: xml_model
.containers
.container
.into_iter()
.map(|container| Container {
id: container.id,
name: Some(container.name),
size: container.size,
position_x: container.position_x,
position_y: container.position_y,
})
.collect(),
zoom_level: Some(xml_model.layout.zoom_level),
pan_x: Some(xml_model.layout.pan_x),
pan_y: Some(xml_model.layout.pan_y),
};

// Metadata can be constructed from various XML fields
let mut metadata = HashMap::new();
metadata.insert("biocheck_version".to_string(), xml_model.biocheck_version);
metadata.insert("description".to_string(), xml_model.description);
metadata.insert("created_date".to_string(), xml_model.created_date);
metadata.insert("modified_date".to_string(), xml_model.modified_date);

BmaModel {
model,
layout,
metadata,
}
}
}
13 changes: 5 additions & 8 deletions src/bin/load_json.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use biodivine_lib_bma_data::bma_model::BmaModel;
use biodivine_lib_bma_data::json_model::JsonBmaModel;
use biodivine_lib_bma_data::traits::JsonSerde;
use std::fs::{read_dir, read_to_string};

/// Iterate through all models and see if they are parse without error.
Expand All @@ -16,9 +16,8 @@ fn test_parse_all_models_in_dir(models_dir: &str) {
let json_data = read_to_string(&model_path)
.unwrap_or_else(|_| panic!("Unable to read file: {}", model_path_str));

let json_model: Result<JsonBmaModel, _> = serde_json::from_str(&json_data);

match json_model {
let model = BmaModel::from_json_str(&json_data);
match model {
Ok(_) => {
println!("Successfully parsed model: `{model_path_str}`.");
}
Expand All @@ -36,10 +35,8 @@ fn main() {
for model_path in selected_model_paths {
println!("Parsing selected model {:?}:", model_path);
let json_data = read_to_string(model_path).expect("Unable to read file");
let json_model: JsonBmaModel =
serde_json::from_str(&json_data).expect("JSON was not well-formatted");
let model = BmaModel::from(json_model);
println!("Internal structure:\n{:?}\n", model);
let model = BmaModel::from_json_str(&json_data).expect("JSON was not well-formatted");
println!("Internal BmaModel structure:\n{:?}\n", model);
}

// 2) now let's iterate through all models and see if they at least parse without error
Expand Down
13 changes: 5 additions & 8 deletions src/bin/load_xml.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use biodivine_lib_bma_data::bma_model::BmaModel;
use biodivine_lib_bma_data::xml_model::XmlBmaModel;
use biodivine_lib_bma_data::traits::XmlSerde;
use std::fs::{read_dir, read_to_string};

/// Iterate through all models and see if they are parse without error.
Expand All @@ -16,9 +16,8 @@ fn test_parse_all_models_in_dir(models_dir: &str) {
let xml_data = read_to_string(&model_path)
.unwrap_or_else(|_| panic!("Unable to read file: {}", model_path_str));

let xml_model: Result<XmlBmaModel, _> = serde_xml_rs::from_str(&xml_data);

match xml_model {
let model = BmaModel::from_xml_str(&xml_data);
match model {
Ok(_) => {
println!("Successfully parsed model: `{model_path_str}`.");
}
Expand All @@ -36,10 +35,8 @@ fn main() {
for model_path in selected_model_paths {
println!("Parsing selected model {:?}:", model_path);
let xml_data = read_to_string(model_path).expect("Unable to read file");
let xml_model: XmlBmaModel =
serde_xml_rs::from_str(&xml_data).expect("XML was not well-formatted");
let model = BmaModel::from(xml_model);
println!("Internal structure:\n{:?}\n", model);
let model = BmaModel::from_xml_str(&xml_data).expect("XML was not well-formatted");
println!("Internal BmaModel structure:\n{:?}\n", model);
}

// 2) now let's iterate through all models and see if they at least parse without error
Expand Down
Loading

0 comments on commit 8ba2160

Please sign in to comment.