template_manage_complex/
template_manage_complex.rs1use rs_teststand::{
21 Engine, Error, GetSeqFileOptions, GetTemplatesFileOptions, PropValType, PropertyObject,
22 PropertyOptions, SequenceFile, StepGroup,
23};
24
25const MAIN_SEQUENCE: &str = "MainSequence";
27const NO_ADAPTER: &str = "";
29const STEP_TEMPLATE: &str = "My_Custom_Step_Template";
31const SEQUENCE_TEMPLATE: &str = "My_Custom_Sequence_Template";
32const VARIABLE_TEMPLATE: &str = "My_Custom_Variable_Template";
33
34fn describe_station_templates(engine: &Engine) -> Result<(), Error> {
41 let templates_file = engine.get_templates_file(GetTemplatesFileOptions::LOAD_IF_NOT_LOADED)?;
42 let root = templates_file
43 .data()?
44 .get_property_object("Root", PropertyOptions::NONE.bits())?;
45
46 println!("Station templates file: {}", templates_file.path()?);
47 for index in 0..root.get_num_elements()? {
48 let category = root.get_property_object_by_offset(index, PropertyOptions::NONE.bits())?;
49 println!(
50 " {}: {} template(s)",
51 category.name()?,
52 category.get_num_elements()?
53 );
54 }
55 Ok(())
56}
57
58fn new_template_group(engine: &Engine) -> Result<PropertyObject, Error> {
60 engine.new_property_object(
61 PropValType::Container,
62 true,
63 "",
64 PropertyOptions::NONE.bits(),
65 )
66}
67
68fn append_template(group: &PropertyObject, template: &PropertyObject) -> Result<(), Error> {
73 let index = group.get_num_elements()?;
74 group.set_num_elements(index + 1, PropertyOptions::NONE.bits())?;
75 group.set_property_object(
76 &format!("[{index}]"),
77 PropertyOptions::NONE.bits(),
78 &template.clone_property("", PropertyOptions::NONE.bits())?,
79 )
80}
81
82fn find_template(group: &PropertyObject, name: &str) -> Result<Option<PropertyObject>, Error> {
84 for index in 0..group.get_num_elements()? {
85 let candidate = group.get_property_object_by_offset(index, PropertyOptions::NONE.bits())?;
86 if candidate.name()? == name {
87 return Ok(Some(candidate));
88 }
89 }
90 Ok(None)
91}
92
93fn require(found: Option<PropertyObject>, name: &'static str) -> Result<PropertyObject, Error> {
95 found.ok_or(Error::UnexpectedType {
96 expected: name,
97 actual: "no template of that name in the group",
98 })
99}
100
101fn step_template(engine: &Engine) -> Result<PropertyObject, Error> {
103 let step = engine.new_step(NO_ADAPTER, "Statement")?;
104 step.set_name(STEP_TEMPLATE)?;
105 step.set_post_expression(r#"Locals.Result = "Hello from step template!""#)?;
106 step.as_property_object()
107}
108
109fn sequence_template(engine: &Engine) -> Result<PropertyObject, Error> {
111 let sequence = engine.new_sequence()?;
112 sequence.set_name(SEQUENCE_TEMPLATE)?;
113
114 let step = engine.new_step(NO_ADAPTER, "Statement")?;
115 step.set_name("Inside_Sequence_Template")?;
116 sequence.insert_step(&step, 0, StepGroup::Main)?;
117
118 sequence.as_property_object()
119}
120
121fn variable_template(engine: &Engine) -> Result<PropertyObject, Error> {
123 let variable =
124 engine.new_property_object(PropValType::String, false, "", PropertyOptions::NONE.bits())?;
125 variable.set_name(VARIABLE_TEMPLATE)?;
126 variable.set_val_string("", PropertyOptions::NONE.bits(), "Template Variable Value")?;
127 Ok(variable)
128}
129
130fn apply_templates(
132 sequence_file: &SequenceFile,
133 step: &PropertyObject,
134 sequence: &PropertyObject,
135 variable: &PropertyObject,
136) -> Result<(), Error> {
137 let main_sequence = sequence_file.get_sequence_by_name(MAIN_SEQUENCE)?;
138
139 let inserted_step = main_sequence.insert_step_from_template(step, 0, StepGroup::Main)?;
143 inserted_step.set_name("Step From Template")?;
144 inserted_step.create_new_unique_step_id()?;
145 println!(" step: {}", inserted_step.name()?);
146
147 let inserted_sequence = sequence_file.insert_sequence_from_template(sequence)?;
148 inserted_sequence.create_new_unique_step_ids()?;
149 println!(
150 " sequence: {} ({} step(s))",
151 inserted_sequence.name()?,
152 inserted_sequence.get_num_steps(StepGroup::Main)?
153 );
154
155 let locals = main_sequence.locals()?;
158 locals.set_property_object(
159 &variable.name()?,
160 PropertyOptions::INSERT_IF_MISSING.bits(),
161 &variable.clone_property("", PropertyOptions::NONE.bits())?,
162 )?;
163 println!(
164 " variable: {} = {:?}",
165 variable.name()?,
166 locals.get_val_string(&variable.name()?, PropertyOptions::NONE.bits())?
167 );
168
169 sequence_file
171 .as_property_object_file()?
172 .inc_change_count()?;
173 Ok(())
174}
175
176fn main() -> Result<(), Box<dyn std::error::Error>> {
177 let engine = Engine::new()?;
178 describe_station_templates(&engine)?;
179
180 println!("\nBuilding an in-memory template group...");
181 let group = new_template_group(&engine)?;
182 append_template(&group, &step_template(&engine)?)?;
183 append_template(&group, &sequence_template(&engine)?)?;
184 append_template(&group, &variable_template(&engine)?)?;
185 println!(" {} template(s) stored", group.get_num_elements()?);
186
187 let step = require(find_template(&group, STEP_TEMPLATE)?, STEP_TEMPLATE)?;
188 let sequence = require(find_template(&group, SEQUENCE_TEMPLATE)?, SEQUENCE_TEMPLATE)?;
189 let variable = require(find_template(&group, VARIABLE_TEMPLATE)?, VARIABLE_TEMPLATE)?;
190
191 let path = std::env::temp_dir().join("rs_teststand_from_templates.seq");
194 let path = path.to_string_lossy().into_owned();
195 engine.new_sequence_file()?.save(&path)?;
196
197 println!("\nApplying templates to the saved file...");
198 let target = engine.get_sequence_file_ex(
199 &path,
200 GetSeqFileOptions::DO_NOT_RUN_LOAD_CALLBACK,
201 rs_teststand::ConflictHandler::Error,
202 )?;
203 apply_templates(&target, &step, &sequence, &variable)?;
204 target.save(&path)?;
205 println!("\nSaved to {path}");
206
207 engine.release_sequence_file_ex(target, PropertyOptions::NONE.bits())?;
208 Ok(())
209}