Skip to main content

PropertyObjectFile

Struct PropertyObjectFile 

Source
pub struct PropertyObjectFile { /* private fields */ }
Expand description

A file holding property objects (PropertyObjectFile).

The file view of something that also has a richer identity, a sequence file reached through as_property_object_file, or a workspace’s options file. This is where a file’s registered types live.

Implementations§

Source§

impl PropertyObjectFile

Source

pub fn save_file_if_modified(&self, prompt: bool) -> Result<bool, Error>

Writes the file to disk if it has changed (PropertyObjectFile.SaveFileIfModified).

Does nothing when the file is unmodified. The path written is whatever path reports.

Pass prompt = false from a host with no operator. With true the engine puts a dialog on screen offering to save, and a headless caller would block on a question nobody can answer. The returned false means only that someone declined at that dialog, so under prompt = false a false should not happen.

§Errors

Error if the COM call fails or returns an unexpected type.

Source

pub fn type_usage_list(&self) -> Result<TypeUsageList, Error>

The types registered in this file (TypeUsageList).

§Errors

Error if the COM call fails or returns an unexpected type.

Examples found in repository?
examples/data_type_manage.rs (line 111)
107fn main() -> Result<(), Box<dyn std::error::Error>> {
108    let engine = Engine::new()?;
109    let sequence_file = engine.new_sequence_file()?;
110    let file = sequence_file.as_property_object_file()?;
111    let types = file.type_usage_list()?;
112
113    types.insert_type(
114        &build_multimeter_type(&engine)?,
115        types.num_types()?,
116        TypeCategory::CustomDataTypes,
117    )?;
118    let coupling = register_enum(
119        &engine,
120        &types,
121        "Coupling",
122        &[("AC", 0.0), ("DC", 1.0)],
123        true,
124    )?;
125
126    // A variable of the enum type, so the change below has an instance to update.
127    let main_sequence = sequence_file.get_sequence_by_name("MainSequence")?;
128    main_sequence.locals()?.new_sub_property(
129        "InputCoupling",
130        PropValType::NamedType,
131        false,
132        "Coupling",
133        INSERT_IF_MISSING,
134    )?;
135
136    println!(
137        "Registered custom data types ({} in file):",
138        types.num_types()?
139    );
140    print_enumerators(&coupling)?;
141
142    // Evolve it: add an enumerator and raise the version.
143    println!(
144        "\nCoupling version before update: {}",
145        coupling.type_version()?
146    );
147    coupling.update_enumerators(&enumerator_array(
148        &engine,
149        &[("AC", 0.0), ("DC", 1.0), ("GND", 2.0)],
150        true,
151    )?)?;
152
153    // Raising the lowest field signals a change the engine applies silently;
154    // raising a higher one marks it as deliberate.
155    let version = coupling.type_version()?;
156    let mut fields = version.split('.');
157    let major: u32 = fields.next().unwrap_or("0").parse().unwrap_or(0);
158    let minor: u32 = fields.next().unwrap_or("0").parse().unwrap_or(0);
159    coupling.set_type_version(&format!("{major}.{}.0.0", minor + 1))?;
160    println!(
161        "Coupling version after  update: {}",
162        coupling.type_version()?
163    );
164
165    println!("\nCoupling now defines (InputCoupling reflects this):");
166    print_enumerators(&coupling)?;
167
168    // Saving does nothing unless the file believes it changed.
169    file.inc_change_count()?;
170    let path = std::env::temp_dir().join("rs_teststand_with_custom_types.seq");
171    sequence_file.save(&path.to_string_lossy())?;
172    println!("\nSaved to {}", path.display());
173
174    engine.release_sequence_file_ex(sequence_file, NO_OPTIONS)?;
175    Ok(())
176}
Source

pub fn inc_change_count(&self) -> Result<(), Error>

Marks the file as modified (IncChangeCount).

Saving does nothing when the file does not believe it has changed, so a change made through the API needs this before the save will write.

§Errors

Error if the COM call fails.

Examples found in repository?
examples/template_manage_complex.rs (line 172)
131fn 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    // Inserting returns the copy on the Step interface, so it can be renamed
140    // and re-identified straight away. Without a new step ID the copy would go
141    // on claiming the prototype's identity.
142    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    // A variable is the easy case: Locals is a property tree, so a clone drops
156    // straight in under the template's own name.
157    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    // A file that does not believe it changed will not write anything.
170    sequence_file
171        .as_property_object_file()?
172        .inc_change_count()?;
173    Ok(())
174}
More examples
Hide additional examples
examples/data_type_manage.rs (line 169)
107fn main() -> Result<(), Box<dyn std::error::Error>> {
108    let engine = Engine::new()?;
109    let sequence_file = engine.new_sequence_file()?;
110    let file = sequence_file.as_property_object_file()?;
111    let types = file.type_usage_list()?;
112
113    types.insert_type(
114        &build_multimeter_type(&engine)?,
115        types.num_types()?,
116        TypeCategory::CustomDataTypes,
117    )?;
118    let coupling = register_enum(
119        &engine,
120        &types,
121        "Coupling",
122        &[("AC", 0.0), ("DC", 1.0)],
123        true,
124    )?;
125
126    // A variable of the enum type, so the change below has an instance to update.
127    let main_sequence = sequence_file.get_sequence_by_name("MainSequence")?;
128    main_sequence.locals()?.new_sub_property(
129        "InputCoupling",
130        PropValType::NamedType,
131        false,
132        "Coupling",
133        INSERT_IF_MISSING,
134    )?;
135
136    println!(
137        "Registered custom data types ({} in file):",
138        types.num_types()?
139    );
140    print_enumerators(&coupling)?;
141
142    // Evolve it: add an enumerator and raise the version.
143    println!(
144        "\nCoupling version before update: {}",
145        coupling.type_version()?
146    );
147    coupling.update_enumerators(&enumerator_array(
148        &engine,
149        &[("AC", 0.0), ("DC", 1.0), ("GND", 2.0)],
150        true,
151    )?)?;
152
153    // Raising the lowest field signals a change the engine applies silently;
154    // raising a higher one marks it as deliberate.
155    let version = coupling.type_version()?;
156    let mut fields = version.split('.');
157    let major: u32 = fields.next().unwrap_or("0").parse().unwrap_or(0);
158    let minor: u32 = fields.next().unwrap_or("0").parse().unwrap_or(0);
159    coupling.set_type_version(&format!("{major}.{}.0.0", minor + 1))?;
160    println!(
161        "Coupling version after  update: {}",
162        coupling.type_version()?
163    );
164
165    println!("\nCoupling now defines (InputCoupling reflects this):");
166    print_enumerators(&coupling)?;
167
168    // Saving does nothing unless the file believes it changed.
169    file.inc_change_count()?;
170    let path = std::env::temp_dir().join("rs_teststand_with_custom_types.seq");
171    sequence_file.save(&path.to_string_lossy())?;
172    println!("\nSaved to {}", path.display());
173
174    engine.release_sequence_file_ex(sequence_file, NO_OPTIONS)?;
175    Ok(())
176}
Source

pub fn data(&self) -> Result<PropertyObject, Error>

The root of the file’s property tree (Data).

Everything a file stores hangs off here, which is how a file with no richer identity, the templates file, for one, is read at all.

§Errors

Error if the COM call fails or returns an unexpected type.

Examples found in repository?
examples/step_insert_from_template.rs (line 36)
33fn describe_templates(engine: &Engine) -> Result<(), Error> {
34    let templates_file = engine.get_templates_file(GetTemplatesFileOptions::LOAD_IF_NOT_LOADED)?;
35    let root = templates_file
36        .data()?
37        .get_property_object("Root", PropertyOptions::NONE.bits())?;
38    for index in 0..root.get_num_elements()? {
39        let category = root.get_property_object_by_offset(index, PropertyOptions::NONE.bits())?;
40        if category.name()? == "Steps" {
41            println!(
42                "Step templates defined on this station: {}",
43                category.get_num_elements()?
44            );
45        }
46    }
47    Ok(())
48}
More examples
Hide additional examples
examples/template_manage_complex.rs (line 43)
40fn 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}
Source

pub fn path(&self) -> Result<String, Error>

The file’s path (Path).

§Errors

Error if the COM call fails or returns an unexpected type.

Examples found in repository?
examples/template_manage_complex.rs (line 46)
40fn 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}
More examples
Hide additional examples
examples/users_manage.rs (line 102)
29fn main() -> Result<(), rs_teststand::Error> {
30    let engine = Engine::new()?;
31
32    // Passing no profile means the user inherits nothing.
33    let user = engine.new_user(None)?;
34    user.set_login_name("operator1")?;
35    user.set_full_name("Test Operator")?;
36    user.set_password("ts-secret")?;
37
38    println!("User: {} ({})", user.login_name()?, user.full_name()?);
39
40    // Check a credential without handling the stored value.
41    println!(
42        "  password 'ts-secret' valid: {}",
43        user.validate_password("ts-secret")?
44    );
45    println!(
46        "  password 'wrong' valid:     {}",
47        user.validate_password("wrong")?
48    );
49
50    println!("  privilege checks:");
51    report_privileges(
52        &user,
53        &[
54            UserPrivilege::Operate,
55            UserPrivilege::Execute,
56            UserPrivilege::Develop,
57            UserPrivilege::Debug,
58            UserPrivilege::EditUsers,
59        ],
60    )?;
61
62    // A privilege can also be named by its full path, which is how a leaf
63    // inside a category is reached.
64    println!(
65        "  Debug.RunSelectedTests:  {}",
66        user.has_privilege_named("Debug.RunSelectedTests")?
67    );
68
69    // The privilege tree is nested: categories hold the individual rights.
70    let privileges = user.privileges()?;
71    let count = privileges.get_num_sub_properties("")?;
72    println!("  privilege tree ({count} categories):");
73    for index in 0..count {
74        let name = privileges.get_nth_sub_property_name("", index, 0)?;
75        let members = privileges
76            .get_property_object(&name, 0)?
77            .get_num_sub_properties("")?;
78        println!("    {name:<12} {members} member(s)");
79    }
80
81    // The station itself, read-only.
82    println!("\nStation:");
83    match engine.current_user()? {
84        Some(current) => println!("  logged in as {}", current.login_name()?),
85        None => println!("  nobody logged in (usual when login is not required)"),
86    }
87    println!(
88        "  is 'operator1' a real account here? {}",
89        engine.user_name_exists("operator1")?
90    );
91
92    // Where accounts actually live. Everything above this point exists only in
93    // memory: `new_user` builds a User, it does not enrol one. A user becomes
94    // part of the station when it is inserted into this file's list and the
95    // file is written.
96    let users_file = engine.users_file()?;
97    let file = users_file.as_property_object_file()?;
98    println!(
99        "
100Users file:"
101    );
102    println!("  path            {}", file.path()?);
103    println!(
104        "  users           {}",
105        users_file.user_list()?.get_num_elements()?
106    );
107    println!(
108        "  groups          {}",
109        users_file.user_group_list()?.get_num_elements()?
110    );
111    println!(
112        "  profiles        {}",
113        users_file.user_profile_list()?.get_num_elements()?
114    );
115
116    // Deliberately not run: it would edit the station this example is reading.
117    // The two calls a host makes to enrol the user built above are
118    //
119    //     users_file.user_list()?.set_num_elements(count + 1, 0)?;   // then fill
120    //     file.save_file_if_modified(false)?;                        // then write
121    //
122    // `false` matters: with `true` the engine puts a save dialog on screen, and
123    // a host with no operator would wait for an answer that never comes.
124    println!(
125        "
126  (this example does not write; enrolling a user would alter the station)"
127    );
128
129    Ok(())
130}
Source

pub fn set_path(&self, path: &str) -> Result<(), Error>

Sets the file’s path (Path).

§Errors

Error if the COM call fails.

Trait Implementations§

Source§

impl Debug for PropertyObjectFile

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.