Skip to content

Commit 01076a2

Browse files
committed
remove lifetime of SBMLDocument
1 parent ed99d03 commit 01076a2

File tree

3 files changed

+42
-28
lines changed

3 files changed

+42
-28
lines changed

src/reader.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl SBMLReader {
3838
///
3939
/// # Returns
4040
/// An SBMLDocument instance containing the parsed model
41-
pub fn from_xml_string(xml: &str) -> SBMLDocument<'static> {
41+
pub fn from_xml_string(xml: &str) -> SBMLDocument {
4242
let reader = Self::new();
4343
// Create an owned String to ensure the data persists
4444
let owned_xml = xml.to_string();
@@ -130,7 +130,7 @@ mod tests {
130130
assert_eq!(list_of_assignment_rules.len(), 0);
131131
}
132132

133-
fn read_sbml_file(path: &PathBuf) -> Result<SBMLDocument<'static>, LibSBMLError> {
133+
fn read_sbml_file(path: &PathBuf) -> Result<SBMLDocument, LibSBMLError> {
134134
let xml = std::fs::read_to_string(path).unwrap();
135135
Ok(SBMLReader::from_xml_string(&xml))
136136
}

src/sbmldoc.rs

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,12 @@ use crate::{
2626
///
2727
/// The SBMLDocument is the top-level container for an SBML model and associated data.
2828
/// It maintains the SBML level and version, and contains a single optional Model.
29-
pub struct SBMLDocument<'a> {
29+
pub struct SBMLDocument {
3030
/// The underlying libSBML document, wrapped in RefCell to allow interior mutability
3131
document: RefCell<UniquePtr<sbmlcxx::SBMLDocument>>,
32-
/// The optional Model contained in this document
33-
model: RefCell<Option<Rc<Model<'a>>>>,
3432
}
3533

36-
impl<'a> SBMLDocument<'a> {
34+
impl SBMLDocument {
3735
/// Creates a new SBMLDocument with the specified SBML level and version.
3836
///
3937
/// # Arguments
@@ -64,7 +62,6 @@ impl<'a> SBMLDocument<'a> {
6462

6563
Self {
6664
document: RefCell::new(document),
67-
model: RefCell::new(None),
6865
}
6966
}
7067

@@ -79,20 +76,11 @@ impl<'a> SBMLDocument<'a> {
7976
///
8077
/// # Returns
8178
/// A new SBMLDocument instance
82-
pub(crate) fn from_unique_ptr(ptr: UniquePtr<sbmlcxx::SBMLDocument>) -> SBMLDocument<'static> {
79+
pub(crate) fn from_unique_ptr(ptr: UniquePtr<sbmlcxx::SBMLDocument>) -> SBMLDocument {
8380
// Wrap the pointer in a RefCell
8481
let document = RefCell::new(ptr);
8582

86-
// Grab the model from the document
87-
let model = document
88-
.borrow_mut()
89-
.as_mut()
90-
.map(|model| Rc::new(Model::from_ptr(model.getModel1())));
91-
92-
SBMLDocument {
93-
document,
94-
model: RefCell::new(model),
95-
}
83+
SBMLDocument { document }
9684
}
9785

9886
/// Returns a reference to the underlying libSBML document.
@@ -147,15 +135,22 @@ impl<'a> SBMLDocument<'a> {
147135
///
148136
/// # Returns
149137
/// A reference to the newly created Model
150-
pub fn create_model(&self, id: &str) -> Rc<Model<'a>> {
151-
let model = Rc::new(Model::new(self, id));
152-
self.model.borrow_mut().replace(Rc::clone(&model));
153-
model
138+
pub fn create_model<'a>(&'a self, id: &str) -> Rc<Model<'a>> {
139+
Rc::new(Model::new(self, id))
154140
}
155141

156142
/// Returns a reference to the Model if one exists.
157-
pub fn model(&self) -> Option<Rc<Model<'a>>> {
158-
self.model.borrow().as_ref().map(Rc::clone)
143+
pub fn model<'a>(&'a self) -> Option<Rc<Model<'a>>> {
144+
// Check if a model exists in the document
145+
let has_model = self.document.borrow_mut().as_mut()?.getModel1().is_null() == false;
146+
147+
if has_model {
148+
Some(Rc::new(Model::from_ptr(
149+
self.document.borrow_mut().as_mut()?.getModel1(),
150+
)))
151+
} else {
152+
None
153+
}
159154
}
160155

161156
/// Converts the SBML document to an XML string representation.
@@ -203,7 +198,7 @@ impl<'a> SBMLDocument<'a> {
203198
}
204199
}
205200

206-
impl<'a> std::fmt::Debug for SBMLDocument<'a> {
201+
impl std::fmt::Debug for SBMLDocument {
207202
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208203
let mut ds = f.debug_struct("SBMLDocument");
209204
ds.field("level", &self.level());
@@ -213,7 +208,7 @@ impl<'a> std::fmt::Debug for SBMLDocument<'a> {
213208
}
214209
}
215210

216-
impl<'a> Default for SBMLDocument<'a> {
211+
impl Default for SBMLDocument {
217212
/// Creates a new SBMLDocument with the default SBML level and version, and FBC package.
218213
///
219214
/// # Returns
@@ -326,4 +321,23 @@ mod tests {
326321
println!("{:?}", doc.plugins());
327322
assert!(!doc.plugins().is_empty());
328323
}
324+
325+
#[test]
326+
fn test_sbmldoc_lifetime_changes() {
327+
// Test that we can create a document and model without lifetime issues
328+
let doc = SBMLDocument::default();
329+
let model = doc.create_model("test_model");
330+
331+
// Test that we can create species and other components
332+
let species = model.create_species("test_species");
333+
assert_eq!(species.id(), "test_species");
334+
335+
// Test that we can get the model back
336+
let retrieved_model = doc.model().expect("Model should exist");
337+
assert_eq!(retrieved_model.id(), "test_model");
338+
339+
// Test that the document doesn't have lifetime parameters
340+
let _xml = doc.to_xml_string();
341+
assert!(!_xml.is_empty());
342+
}
329343
}

tests/e2e.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod tests {
66
fn test_sbmldoc_debug() {
77
let doc = create_doc();
88
let debug_string = format!("{:?}", doc);
9-
insta::assert_snapshot!(debug_string, @r#"SBMLDocument { level: 3, version: 2, model: Some(Model { id: "test_model", name: "", list_of_species: [Species { id: "species", name: Some("species"), compartment: Some("compartment"), initial_amount: None, initial_concentration: Some(1.0), unit: Some("mole"), boundary_condition: Some(false), constant: false, has_only_substance_units: Some(false) }, Species { id: "product", name: Some("product"), compartment: Some("compartment"), initial_amount: None, initial_concentration: Some(1.0), unit: Some("mole"), boundary_condition: Some(false), constant: false, has_only_substance_units: Some(false) }], list_of_compartments: [Compartment { id: "compartment", name: Some("compartment"), spatial_dimensions: None, unit: Some("ml"), size: Some(1.0), volume: Some(1.0), outside: None, constant: Some(true) }], list_of_unit_definitions: [UnitDefinition { id: "ml", name: Some("milliliter"), units: [Unit { kind: Litre, exponent: 1, multiplier: 1.0, scale: -3, offset: 0.0 }] }, UnitDefinition { id: "mole", name: Some("mole"), units: [Unit { kind: Mole, exponent: 1, multiplier: 1.0, scale: 0, offset: 0.0 }, Unit { kind: Litre, exponent: -1, multiplier: 1.0, scale: 0, offset: 0.0 }] }, UnitDefinition { id: "kelvin", name: Some("kelvin"), units: [Unit { kind: Kelvin, exponent: 1, multiplier: 1.0, scale: 0, offset: 0.0 }] }], list_of_reactions: [Reaction { id: "reaction", name: Some("reaction"), reversible: None, compartment: None, reactants: RefCell { value: [SpeciesReference { species: "species", stoichiometry: 1.0, constant: false }] }, products: RefCell { value: [SpeciesReference { species: "product", stoichiometry: 1.0, constant: false }] }, modifiers: RefCell { value: [] } }], list_of_parameters: [Parameter { id: "T", name: None, value: Some(310.0), units: Some("kelvin"), constant: Some(true) }, Parameter { id: "Km", name: None, value: Some(1.0), units: Some("mole"), constant: Some(true) }], list_of_rate_rules: [Rule { type: Ok(RateRule), variable: "product", formula: "kcat * substrate / (substrate + Km)" }], list_of_assignment_rules: [Rule { type: Ok(AssignmentRule), variable: "x", formula: "T * kcat * substrate / (T + Km)" }], list_of_objectives: [], list_of_flux_bounds: [FluxBound { id: Some("fb1"), reaction: Some("reaction"), operation: LessEqual }] }) }"#);
9+
insta::assert_snapshot!(debug_string, @r#"SBMLDocument { level: 3, version: 2, model: Some(Model { id: "test_model", name: "", list_of_species: [Species { id: "species", name: Some("species"), compartment: Some("compartment"), initial_amount: None, initial_concentration: Some(1.0), unit: Some("mole"), boundary_condition: Some(false), constant: false, has_only_substance_units: Some(false) }, Species { id: "product", name: Some("product"), compartment: Some("compartment"), initial_amount: None, initial_concentration: Some(1.0), unit: Some("mole"), boundary_condition: Some(false), constant: false, has_only_substance_units: Some(false) }], list_of_compartments: [Compartment { id: "compartment", name: Some("compartment"), spatial_dimensions: None, unit: Some("ml"), size: Some(1.0), volume: Some(1.0), outside: None, constant: Some(true) }], list_of_unit_definitions: [UnitDefinition { id: "ml", name: Some("milliliter"), units: [Unit { kind: Litre, exponent: 1, multiplier: 1.0, scale: -3, offset: 0.0 }] }, UnitDefinition { id: "mole", name: Some("mole"), units: [Unit { kind: Mole, exponent: 1, multiplier: 1.0, scale: 0, offset: 0.0 }, Unit { kind: Litre, exponent: -1, multiplier: 1.0, scale: 0, offset: 0.0 }] }, UnitDefinition { id: "kelvin", name: Some("kelvin"), units: [Unit { kind: Kelvin, exponent: 1, multiplier: 1.0, scale: 0, offset: 0.0 }] }], list_of_reactions: [Reaction { id: "reaction", name: Some("reaction"), reversible: None, compartment: None, reactants: RefCell { value: [SpeciesReference { species: "species", stoichiometry: 1.0, constant: false }] }, products: RefCell { value: [SpeciesReference { species: "product", stoichiometry: 1.0, constant: false }] }, modifiers: RefCell { value: [] } }], list_of_parameters: [Parameter { id: "T", name: None, value: Some(310.0), units: Some("kelvin"), constant: Some(true) }, Parameter { id: "Km", name: None, value: Some(1.0), units: Some("mole"), constant: Some(true) }], list_of_rate_rules: [Rule { type: Ok(RateRule), variable: "product", formula: "kcat * substrate / (substrate + Km)" }], list_of_assignment_rules: [Rule { type: Ok(AssignmentRule), variable: "x", formula: "T * kcat * substrate / (T + Km)" }], list_of_objectives: [Objective { id: "objective", obj_type: Maximize, flux_objectives: [FluxObjective { id: Some("fo1"), reaction: Some("reaction"), coefficient: Some(1.0) }] }], list_of_flux_bounds: [FluxBound { id: Some("fb1"), reaction: Some("reaction"), operation: LessEqual }] }) }"#);
1010
}
1111

1212
#[test]
@@ -23,7 +23,7 @@ mod tests {
2323
assert_eq!(xml_string, xml_string2);
2424
}
2525

26-
fn create_doc() -> SBMLDocument<'static> {
26+
fn create_doc() -> SBMLDocument {
2727
let doc = SBMLDocument::default();
2828
let model = doc.create_model("test_model");
2929

0 commit comments

Comments
 (0)