1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::bindings::da::{
IOPCBrowseServerAddressSpace, tagOPCBROWSEDIRECTION, tagOPCBROWSETYPE, tagOPCNAMESPACETYPE,
};
use crate::opc_da::{
client::StringIterator,
com_utils::{LocalPointer, RemotePointer},
errors::{OpcError, OpcResult},
};
/// Server address space browsing functionality.
///
/// Provides methods to navigate and discover items in the OPC server's address space.
/// Supports hierarchical and flat address spaces with filtering capabilities.
pub trait BrowseServerAddressSpaceTrait {
fn interface(&self) -> OpcResult<&IOPCBrowseServerAddressSpace>;
/// Queries the organization type of the server's address space.
///
/// # Returns
/// The namespace type (hierarchical or flat)
fn query_organization(&self) -> OpcResult<tagOPCNAMESPACETYPE> {
// SAFETY: Calling COM interface method QueryOrganization.
unsafe { Ok(self.interface()?.QueryOrganization()?) }
}
/// Changes the current position in the server's address space.
///
/// # Arguments
/// * `browse_direction` - Direction to move (up, down, or to)
/// * `position` - Target position string (branch name for down/to)
///
/// # Returns
/// Result indicating success or failure of position change
fn change_browse_position(
&self,
browse_direction: tagOPCBROWSEDIRECTION,
position: &str,
) -> OpcResult<()> {
let position = LocalPointer::from(position);
// SAFETY: Calling COM interface method ChangeBrowsePosition with valid position string.
unsafe {
Ok(self
.interface()?
.ChangeBrowsePosition(browse_direction, position.as_pwstr())?)
}
}
/// Browses available item IDs at the current position.
///
/// # Arguments
/// * `browse_type` - Type of items to browse (leaf, branch, or flat)
/// * `filter_criteria` - Pattern for filtering items
/// * `datatype_filter` - VT_* type to filter by (0 for all)
/// * `access_rights_filter` - Required access rights
///
/// # Returns
/// Enumerator for matching item IDs
fn browse_opc_item_ids<S0>(
&self,
browse_type: tagOPCBROWSETYPE,
filter_criteria: Option<S0>,
data_type_filter: u16,
access_rights_filter: u32,
) -> OpcResult<StringIterator>
where
S0: AsRef<str>,
{
let filter_criteria = LocalPointer::from_option(filter_criteria);
// SAFETY: Calling COM interface method BrowseOPCItemIDs with valid filter string.
unsafe {
let iter = self.interface()?.BrowseOPCItemIDs(
browse_type,
filter_criteria.as_pwstr(),
data_type_filter,
access_rights_filter,
)?;
Ok(StringIterator::new(iter))
}
}
/// Gets fully qualified item ID from a leaf item.
///
/// # Arguments
/// * `item_data_id` - Item name at current position
///
/// # Returns
/// Fully qualified item ID string
fn get_item_id(&self, item_data_id: &str) -> OpcResult<String> {
let item_data_id = LocalPointer::from(item_data_id);
// SAFETY: Calling COM interface method GetItemID with valid item_data_id string.
let output = unsafe { self.interface()?.GetItemID(item_data_id.as_pwstr())? };
let ptr = RemotePointer::from(output);
ptr.try_into().map_err(OpcError::from)
}
/// Browses available access paths for an item.
///
/// # Arguments
/// * `item_id` - Fully qualified item ID
///
/// # Returns
/// Enumerator for available access paths
fn browse_access_paths(&self, item_id: &str) -> OpcResult<StringIterator> {
let item_id = LocalPointer::from(item_id);
// SAFETY: Calling COM interface method BrowseAccessPaths with valid item_id string.
unsafe {
let iter = self.interface()?.BrowseAccessPaths(item_id.as_pwstr())?;
Ok(StringIterator::new(iter))
}
}
}