Skip to content

Commit 4cdaaaa

Browse files
committed
provide IntoId trait for ID extraction
1 parent b5fe15a commit 4cdaaaa

File tree

9 files changed

+160
-27
lines changed

9 files changed

+160
-27
lines changed

src/compartment.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::{cell::RefCell, pin::Pin, rc::Rc};
1212
use autocxx::c_uint;
1313
use cxx::let_cxx_string;
1414

15-
use crate::{inner, model::Model, pin_ptr, sbmlcxx, sbo_term, upcast_annotation};
15+
use crate::{inner, into_id, model::Model, pin_ptr, sbmlcxx, sbo_term, upcast_annotation};
1616

1717
/// A safe wrapper around the libSBML Compartment class.
1818
///
@@ -30,6 +30,9 @@ inner!(sbmlcxx::Compartment, Compartment<'a>);
3030
// Set the annotation trait for the Compartment struct
3131
upcast_annotation!(Compartment<'a>, sbmlcxx::Compartment, sbmlcxx::SBase);
3232

33+
// Set the into_id trait for the Compartment struct
34+
into_id!(&Rc<Compartment<'_>>, id);
35+
3336
impl<'a> Compartment<'a> {
3437
/// Creates a new Compartment instance within the given Model.
3538
///

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub mod traits {
2121
pub mod annotation;
2222
pub mod fromptr;
2323
pub mod inner;
24+
pub mod intoid;
2425
}
2526

2627
/// Module providing upcast functionality
@@ -77,6 +78,7 @@ pub mod prelude {
7778
pub use crate::species::*;
7879
pub use crate::speciesref::*;
7980
pub use crate::traits::annotation::*;
81+
pub use crate::traits::intoid::*;
8082
pub use crate::unit::*;
8183
pub use crate::unitdef::*;
8284
}

src/macros.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,14 @@ macro_rules! sbo_term {
253253
}
254254
};
255255
}
256+
257+
#[macro_export]
258+
macro_rules! into_id {
259+
($type:ty, $property:ident) => {
260+
impl<'a> crate::traits::intoid::IntoId<'a> for $type {
261+
fn into_id(self) -> &'a str {
262+
Box::leak(self.$property().into_boxed_str())
263+
}
264+
}
265+
};
266+
}

src/modref.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
use std::{cell::RefCell, pin::Pin};
1111

1212
use crate::{
13-
inner, pin_ptr, reaction::Reaction, sbmlcxx, sbo_term, upcast, upcast_annotation, upcast_pin,
13+
inner, pin_ptr, prelude::IntoId, reaction::Reaction, sbmlcxx, sbo_term, upcast,
14+
upcast_annotation, upcast_pin,
1415
};
1516
use cxx::let_cxx_string;
1617

@@ -115,8 +116,8 @@ impl<'a> ModifierSpeciesReferenceBuilder<'a> {
115116
///
116117
/// # Returns
117118
/// A new ModifierSpeciesReferenceBuilder instance
118-
pub fn new(reaction: &Reaction<'a>, sid: &str) -> Self {
119-
let modifier_reference = ModifierSpeciesReference::new(reaction, sid);
119+
pub fn new(reaction: &Reaction<'a>, sid: impl IntoId<'a>) -> Self {
120+
let modifier_reference = ModifierSpeciesReference::new(reaction, sid.into_id());
120121
Self { modifier_reference }
121122
}
122123

src/parameter.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::{cell::RefCell, pin::Pin, rc::Rc};
1313
use cxx::let_cxx_string;
1414

1515
use crate::{
16-
inner,
16+
inner, into_id,
1717
model::Model,
1818
pin_ptr,
1919
sbmlcxx::{self},
@@ -36,6 +36,9 @@ inner!(sbmlcxx::Parameter, Parameter<'a>);
3636
// Set the annotation trait for the Parameter struct
3737
upcast_annotation!(Parameter<'a>, sbmlcxx::Parameter, sbmlcxx::SBase);
3838

39+
// Set the into_id trait for the Compartment struct
40+
into_id!(&Rc<Parameter<'_>>, id);
41+
3942
impl<'a> Parameter<'a> {
4043
/// Creates a new Parameter instance within the given Model.
4144
///

src/reaction.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ use std::{cell::RefCell, pin::Pin, rc::Rc};
1313
use cxx::let_cxx_string;
1414

1515
use crate::{
16-
inner,
16+
inner, into_id,
1717
model::Model,
1818
modref::{ModifierSpeciesReference, ModifierSpeciesReferenceBuilder},
1919
pin_ptr,
20+
prelude::IntoId,
2021
sbmlcxx::{self},
2122
sbo_term,
2223
speciesref::{SpeciesReference, SpeciesReferenceBuilder, SpeciesReferenceType},
@@ -42,6 +43,9 @@ inner!(sbmlcxx::Reaction, Reaction<'a>);
4243
// Set the annotation trait for the Reaction struct
4344
upcast_annotation!(Reaction<'a>, sbmlcxx::Reaction, sbmlcxx::SBase);
4445

46+
// Set the into_id trait for the Reaction struct
47+
into_id!(&Rc<Reaction<'_>>, id);
48+
4549
impl<'a> Reaction<'a> {
4650
/// Creates a new Reaction instance within the given Model.
4751
///
@@ -116,7 +120,11 @@ impl<'a> Reaction<'a> {
116120
///
117121
/// # Returns
118122
/// A reference-counted pointer to the new SpeciesReference
119-
pub fn create_product(&self, sid: &str, stoichiometry: f64) -> Rc<SpeciesReference<'a>> {
123+
pub fn create_product(
124+
&self,
125+
sid: impl IntoId<'a>,
126+
stoichiometry: f64,
127+
) -> Rc<SpeciesReference<'a>> {
120128
let product = Rc::new(SpeciesReference::new(
121129
self,
122130
sid,
@@ -134,7 +142,7 @@ impl<'a> Reaction<'a> {
134142
///
135143
/// # Returns
136144
/// A SpeciesReferenceBuilder for configuring and creating the product
137-
pub fn build_product(&self, sid: &str) -> SpeciesReferenceBuilder<'a> {
145+
pub fn build_product(&self, sid: impl IntoId<'a>) -> SpeciesReferenceBuilder<'a> {
138146
SpeciesReferenceBuilder::new(&self, sid, SpeciesReferenceType::Product)
139147
}
140148

@@ -169,7 +177,11 @@ impl<'a> Reaction<'a> {
169177
///
170178
/// # Returns
171179
/// A reference-counted pointer to the new SpeciesReference
172-
pub fn create_reactant(&self, sid: &str, stoichiometry: f64) -> Rc<SpeciesReference<'a>> {
180+
pub fn create_reactant(
181+
&self,
182+
sid: impl IntoId<'a>,
183+
stoichiometry: f64,
184+
) -> Rc<SpeciesReference<'a>> {
173185
let reactant = Rc::new(SpeciesReference::new(
174186
self,
175187
sid,
@@ -187,7 +199,7 @@ impl<'a> Reaction<'a> {
187199
///
188200
/// # Returns
189201
/// A SpeciesReferenceBuilder for configuring and creating the reactant
190-
pub fn build_reactant(&self, sid: &str) -> SpeciesReferenceBuilder<'a> {
202+
pub fn build_reactant(&self, sid: impl IntoId<'a>) -> SpeciesReferenceBuilder<'a> {
191203
SpeciesReferenceBuilder::new(&self, sid, SpeciesReferenceType::Reactant)
192204
}
193205

@@ -234,7 +246,7 @@ impl<'a> Reaction<'a> {
234246
///
235247
/// # Returns
236248
/// A ModifierSpeciesReferenceBuilder for configuring and creating the modifier
237-
pub fn build_modifier(&self, sid: &str) -> ModifierSpeciesReferenceBuilder<'a> {
249+
pub fn build_modifier(&self, sid: impl IntoId<'a>) -> ModifierSpeciesReferenceBuilder<'a> {
238250
ModifierSpeciesReferenceBuilder::new(&self, sid)
239251
}
240252
/// Returns a reference to the modifiers of this reaction.
@@ -324,8 +336,8 @@ impl<'a> ReactionBuilder<'a> {
324336
///
325337
/// # Returns
326338
/// The builder instance for method chaining
327-
pub fn product(self, sid: &str, stoichiometry: f64) -> Self {
328-
self.reaction.create_product(sid, stoichiometry);
339+
pub fn product(self, sid: impl IntoId<'a>, stoichiometry: f64) -> Self {
340+
self.reaction.create_product(sid.into_id(), stoichiometry);
329341
self
330342
}
331343

@@ -337,8 +349,8 @@ impl<'a> ReactionBuilder<'a> {
337349
///
338350
/// # Returns
339351
/// The builder instance for method chaining
340-
pub fn reactant(self, sid: &str, stoichiometry: f64) -> Self {
341-
self.reaction.create_reactant(sid, stoichiometry);
352+
pub fn reactant(self, sid: impl IntoId<'a>, stoichiometry: f64) -> Self {
353+
self.reaction.create_reactant(sid.into_id(), stoichiometry);
342354
self
343355
}
344356

@@ -349,10 +361,11 @@ impl<'a> ReactionBuilder<'a> {
349361
///
350362
/// # Returns
351363
/// The builder instance for method chaining
352-
pub fn modifier(self, sid: &str) -> Self {
353-
self.reaction.create_modifier(sid);
364+
pub fn modifier(self, sid: impl IntoId<'a>) -> Self {
365+
self.reaction.create_modifier(sid.into_id());
354366
self
355367
}
368+
356369
pub fn build(self) -> Rc<Reaction<'a>> {
357370
self.reaction
358371
}

src/species.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ use std::{cell::RefCell, pin::Pin, rc::Rc};
1313
use cxx::let_cxx_string;
1414

1515
use crate::{
16-
inner,
16+
inner, into_id,
1717
model::Model,
1818
pin_ptr,
19+
prelude::IntoId,
1920
sbmlcxx::{self},
2021
sbo_term,
2122
traits::fromptr::FromPtr,
@@ -36,6 +37,9 @@ inner!(sbmlcxx::Species, Species<'a>);
3637
// Set the annotation trait for the Species struct
3738
upcast_annotation!(Species<'a>, sbmlcxx::Species, sbmlcxx::SBase);
3839

40+
// Set the into_id trait for the Species struct
41+
into_id!(&Rc<Species<'_>>, id);
42+
3943
impl<'a> Species<'a> {
4044
/// Creates a new Species instance within the given Model.
4145
///
@@ -120,7 +124,8 @@ impl<'a> Species<'a> {
120124
///
121125
/// # Arguments
122126
/// * `compartment` - The identifier of the compartment
123-
pub fn set_compartment(&self, compartment: &str) {
127+
pub fn set_compartment(&self, compartment: impl IntoId<'a>) {
128+
let compartment = compartment.into_id();
124129
let_cxx_string!(compartment = compartment);
125130
self.inner
126131
.borrow_mut()
@@ -311,7 +316,7 @@ impl<'a> SpeciesBuilder<'a> {
311316
///
312317
/// # Arguments
313318
/// * `compartment` - The compartment identifier
314-
pub fn compartment(self, compartment: &str) -> Self {
319+
pub fn compartment(self, compartment: impl IntoId<'a>) -> Self {
315320
self.species.set_compartment(compartment);
316321
self
317322
}

src/speciesref.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::{cell::RefCell, pin::Pin, rc::Rc};
1212

1313
use crate::{
1414
inner, pin_ptr,
15+
prelude::IntoId,
1516
reaction::Reaction,
1617
sbmlcxx::{self},
1718
sbo_term,
@@ -46,7 +47,11 @@ impl<'a> SpeciesReference<'a> {
4647
///
4748
/// # Returns
4849
/// A new SpeciesReference instance
49-
pub(crate) fn new(reaction: &Reaction<'a>, sid: &str, ref_type: SpeciesReferenceType) -> Self {
50+
pub(crate) fn new(
51+
reaction: &Reaction<'a>,
52+
sid: impl IntoId<'a>,
53+
ref_type: SpeciesReferenceType,
54+
) -> Self {
5055
let species_reference_ptr = match ref_type {
5156
SpeciesReferenceType::Reactant => {
5257
reaction.inner().borrow_mut().as_mut().createReactant()
@@ -60,7 +65,7 @@ impl<'a> SpeciesReference<'a> {
6065
// We need to fall back to custom wrappers for the species reference
6166
// because autocxx does not support setting the species reference's species
6267
// most likely because it is a virtual base class.
63-
let_cxx_string!(sid = sid);
68+
let_cxx_string!(sid = sid.into_id());
6469
let simple_spec_ref = upcast_pin!(
6570
species_reference,
6671
sbmlcxx::SpeciesReference,
@@ -98,14 +103,14 @@ impl<'a> SpeciesReference<'a> {
98103
///
99104
/// # Arguments
100105
/// * `species` - The species to set
101-
pub fn set_species(&self, species: &str) {
106+
pub fn set_species(&self, species: impl IntoId<'a>) {
102107
let simple_spec_ref = upcast!(
103108
self,
104109
sbmlcxx::SpeciesReference,
105110
sbmlcxx::SimpleSpeciesReference
106111
);
107112

108-
let_cxx_string!(species = species);
113+
let_cxx_string!(species = species.into_id());
109114
simple_spec_ref.setSpecies(&species);
110115
}
111116

@@ -193,10 +198,14 @@ impl<'a> SpeciesReferenceBuilder<'a> {
193198
///
194199
/// # Returns
195200
/// A new SpeciesReferenceBuilder instance
196-
pub fn new(reaction: &Reaction<'a>, sid: &str, ref_type: SpeciesReferenceType) -> Self {
201+
pub fn new(
202+
reaction: &Reaction<'a>,
203+
sid: impl IntoId<'a>,
204+
ref_type: SpeciesReferenceType,
205+
) -> Self {
197206
let species_reference = match ref_type {
198-
SpeciesReferenceType::Reactant => reaction.create_reactant(sid, 1.0),
199-
SpeciesReferenceType::Product => reaction.create_product(sid, 1.0),
207+
SpeciesReferenceType::Reactant => reaction.create_reactant(sid.into_id(), 1.0),
208+
SpeciesReferenceType::Product => reaction.create_product(sid.into_id(), 1.0),
200209
};
201210

202211
Self { species_reference }

src/traits/intoid.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//! Trait for converting strings into string references with appropriate lifetimes
2+
//!
3+
//! This module provides functionality to convert owned Strings and string slices
4+
//! into string references with proper lifetime management. This is useful
5+
//! when working with APIs that require string references.
6+
//!
7+
//! # Examples
8+
//! ```
9+
//! use sbml::traits::intoid::IntoId;
10+
//!
11+
//! let owned = String::from("species1");
12+
//! let str_ref = owned.into_id(); // Borrows from owned
13+
//!
14+
//! let slice = "species2";
15+
//! let str_ref = slice.into_id(); // Simply returns the slice
16+
//! ```
17+
18+
/// Trait for converting a type into a string reference with appropriate lifetime
19+
///
20+
/// This trait provides a way to convert strings into references with proper
21+
/// lifetime management instead of leaking memory.
22+
pub trait IntoId<'a> {
23+
/// Converts self into a string reference with appropriate lifetime
24+
fn into_id(self) -> &'a str;
25+
}
26+
27+
impl<'a> IntoId<'a> for &'a String {
28+
/// Converts a reference to String into a string slice
29+
fn into_id(self) -> &'a str {
30+
self.as_str()
31+
}
32+
}
33+
34+
impl<'a> IntoId<'a> for &'a str {
35+
/// Simply returns the string slice with its existing lifetime
36+
fn into_id(self) -> &'a str {
37+
self
38+
}
39+
}
40+
41+
// Optional: Implementation for owned String that returns a reference to a newly created String
42+
// Note: This requires the caller to maintain the String while using the reference
43+
impl<'a> IntoId<'a> for &'a mut String {
44+
fn into_id(self) -> &'a str {
45+
self.as_str()
46+
}
47+
}
48+
49+
#[cfg(test)]
50+
mod tests {
51+
use crate::into_id;
52+
53+
use super::*;
54+
55+
#[test]
56+
fn test_into_id() {
57+
// Test with a String reference
58+
let owned = String::from("species1");
59+
let str_ref = (&owned).into_id();
60+
assert_eq!(str_ref, "species1");
61+
62+
// Test with a string slice
63+
let slice = "species2";
64+
let str_ref = slice.into_id();
65+
assert_eq!(str_ref, "species2");
66+
67+
// Test with a struct
68+
struct TestStruct {
69+
id: String,
70+
}
71+
72+
impl TestStruct {
73+
fn id(&self) -> String {
74+
self.id.clone()
75+
}
76+
}
77+
78+
into_id!(TestStruct, id);
79+
80+
let test_struct = TestStruct {
81+
id: String::from("species3"),
82+
};
83+
let str_ref = test_struct.id();
84+
assert_eq!(str_ref, "species3");
85+
}
86+
}

0 commit comments

Comments
 (0)