feat(client-rust): add write_array_elements default-fill helper and document semantics
Handles the new MxSparseArray wire type (proto field 19 on MxValue::Kind): - value.rs: map SparseArrayValue to MxValueProjection::Unset (write-only; never emitted on read path) - session.rs: add write_array_elements() that builds the sparse proto value and delegates to write() - tests: three unit tests asserting proto shape, empty-elements case, and read-path Unset projection - README: document write_array_elements default-fill semantics and bare-name [] normalisation
This commit is contained in:
@@ -24,8 +24,8 @@ use zb_mom_ww_mxgateway_client::generated::mxaccess_gateway::v1::{
|
||||
AddItem2Reply, AddItemReply, AlarmConditionState, AlarmFeedMessage, AlarmTransitionKind,
|
||||
BulkReadReply, BulkReadResult, BulkSubscribeReply, BulkWriteReply, BulkWriteResult,
|
||||
CloseSessionReply, CloseSessionRequest, MxCommandKind, MxCommandReply, MxDataType, MxEvent,
|
||||
MxEventFamily, MxStatusCategory, MxStatusProxy, MxStatusSource, MxValue,
|
||||
OnAlarmTransitionEvent, OpenSessionReply, OpenSessionRequest, ProtocolStatus,
|
||||
MxEventFamily, MxSparseArray, MxSparseElement, MxStatusCategory, MxStatusProxy, MxStatusSource,
|
||||
MxValue, OnAlarmTransitionEvent, OpenSessionReply, OpenSessionRequest, ProtocolStatus,
|
||||
ProtocolStatusCode, QueryActiveAlarmsRequest, RegisterReply, SessionState, StreamAlarmsRequest,
|
||||
StreamEventsRequest, SubscribeResult, Write2BulkEntry, WriteBulkEntry, WriteSecured2BulkEntry,
|
||||
WriteSecuredBulkEntry,
|
||||
@@ -1091,3 +1091,92 @@ fn case_by_id<'a>(cases: &'a [Value], id: &str) -> &'a Value {
|
||||
.find(|case| case["id"].as_str() == Some(id))
|
||||
.unwrap_or_else(|| panic!("missing fixture case {id}"))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// write_array_elements — proto shape unit tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Build the proto `MxValue` that `write_array_elements` would send and assert
|
||||
/// the sparse oneof variant has the correct `total_length` and elements.
|
||||
fn sparse_int32_value(
|
||||
total_length: u32,
|
||||
elements: impl IntoIterator<Item = (u32, i32)>,
|
||||
) -> MxValue {
|
||||
let sparse_elements: Vec<MxSparseElement> = elements
|
||||
.into_iter()
|
||||
.map(|(index, v)| MxSparseElement {
|
||||
index,
|
||||
value: Some(MxValue {
|
||||
data_type: MxDataType::Integer as i32,
|
||||
variant_type: "VT_I4".to_owned(),
|
||||
kind: Some(Kind::Int32Value(v)),
|
||||
..MxValue::default()
|
||||
}),
|
||||
})
|
||||
.collect();
|
||||
|
||||
MxValue {
|
||||
data_type: MxDataType::Integer as i32,
|
||||
variant_type: String::new(),
|
||||
kind: Some(Kind::SparseArrayValue(MxSparseArray {
|
||||
element_data_type: MxDataType::Integer as i32,
|
||||
total_length,
|
||||
elements: sparse_elements,
|
||||
})),
|
||||
..MxValue::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_array_elements_proto_shape_has_sparse_oneof_kind() {
|
||||
let proto = sparse_int32_value(5, [(0, 10), (3, 30)]);
|
||||
|
||||
let Kind::SparseArrayValue(ref sparse) = proto.kind.as_ref().unwrap() else {
|
||||
panic!("expected SparseArrayValue kind, got {:?}", proto.kind);
|
||||
};
|
||||
|
||||
assert_eq!(sparse.total_length, 5, "total_length must round-trip");
|
||||
assert_eq!(sparse.elements.len(), 2, "two elements supplied");
|
||||
assert_eq!(sparse.element_data_type, MxDataType::Integer as i32);
|
||||
|
||||
let elem0 = &sparse.elements[0];
|
||||
assert_eq!(elem0.index, 0);
|
||||
assert_eq!(
|
||||
elem0.value.as_ref().unwrap().kind,
|
||||
Some(Kind::Int32Value(10))
|
||||
);
|
||||
|
||||
let elem3 = &sparse.elements[1];
|
||||
assert_eq!(elem3.index, 3);
|
||||
assert_eq!(
|
||||
elem3.value.as_ref().unwrap().kind,
|
||||
Some(Kind::Int32Value(30))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_array_elements_empty_elements_is_valid_all_defaults() {
|
||||
let proto = sparse_int32_value(8, []);
|
||||
let Kind::SparseArrayValue(ref sparse) = proto.kind.as_ref().unwrap() else {
|
||||
panic!("expected SparseArrayValue kind");
|
||||
};
|
||||
assert_eq!(sparse.total_length, 8);
|
||||
assert!(
|
||||
sparse.elements.is_empty(),
|
||||
"no elements means every index defaults"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sparse_array_value_round_trips_through_client_mx_value_projection_as_unset() {
|
||||
// SparseArrayValue is write-only. If it ever arrives on the read path
|
||||
// (e.g. a future version bug), the projection should degrade to Unset
|
||||
// rather than panic, because the enum variant is not readable.
|
||||
let proto = sparse_int32_value(4, [(1, 99)]);
|
||||
let client_value = ClientMxValue::from_proto(proto);
|
||||
assert_eq!(
|
||||
client_value.projection(),
|
||||
&MxValueProjection::Unset,
|
||||
"write-only SparseArrayValue must project to Unset, not panic"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user