Skip to content

Commit 0158ec7

Browse files
committed
Cleanup NullStr a bit, add basic tests
1 parent a3c3789 commit 0158ec7

1 file changed

Lines changed: 48 additions & 68 deletions

File tree

gateway-messages/src/lib.rs

Lines changed: 48 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ pub use hubpack::{SerializedSize, deserialize, serialize};
2424
pub use mgs_to_sp::*;
2525
pub use sp_to_mgs::*;
2626

27-
use crate::nullstr::NullStr;
28-
2927
/// The SP should detach an attached serial console client if it has not heard
3028
/// from it in this long (based on the assumption that it has gone away without
3129
/// sending an explicit detach).
@@ -284,16 +282,23 @@ impl From<UpdateId> for uuid::Uuid {
284282
mod nullstr {
285283
use super::*;
286284

285+
/// A reusable type that implements a fixed-max-capacity string where the
286+
/// unused capacity is always guaranteed to be zero-filled. This is used
287+
/// for strings sent over the wire using [`hubpack`], which requires fixed-size
288+
/// items.
289+
///
290+
/// It is not intended for this type to be part of the public API, see
291+
/// [`SpComponent`] for usage guidance.
287292
#[derive(Clone, Copy, PartialEq, Eq, Hash, SerializedSize)]
288293
pub struct NullStr<const N: usize> {
289294
contents: [u8; N],
290295
}
291296

292297
impl<const N: usize> NullStr<N> {
293-
/// Interpret the component name as a human-readable string.
298+
/// Interpret the content as a human-readable string.
294299
///
295-
/// Our current expectation of component names is that this should never
296-
/// fail (i.e., we're always storing component names as human-readable
300+
/// Our current expectation of contents is that this should never
301+
/// fail (i.e., we're always storing contents as human-readable
297302
/// strings), but because we reconstitute components from network messages
298303
/// we still need to check.
299304
pub fn as_str(&self) -> Option<&str> {
@@ -470,7 +475,10 @@ mod nullstr {
470475
}
471476

472477
/// Identifier for a single component managed by an SP.
473-
#[derive(Clone, Copy, PartialEq, Eq, Hash, SerializedSize)]
478+
#[derive(
479+
Clone, Copy, PartialEq, Eq, Hash, SerializedSize, Serialize, Deserialize,
480+
)]
481+
#[serde(transparent)]
474482
pub struct SpComponent {
475483
/// The ID of the component.
476484
///
@@ -483,34 +491,6 @@ pub struct SpComponent {
483491
id: nullstr::NullStr<{ Self::MAX_ID_LENGTH }>,
484492
}
485493

486-
impl Serialize for SpComponent {
487-
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
488-
where
489-
S: serde::Serializer,
490-
{
491-
// TODO(AJM): I don't think we can just derive deserialize here because I think the old impl
492-
// served as an implicit "flatten", and we don't want to introduce another level of nesting.
493-
nullstr::NullStr::<{ Self::MAX_ID_LENGTH }>::serialize(
494-
&self.id, serializer,
495-
)
496-
}
497-
}
498-
499-
impl<'de> Deserialize<'de> for SpComponent {
500-
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
501-
where
502-
D: serde::Deserializer<'de>,
503-
{
504-
// TODO(AJM): I don't think we can just derive deserialize here because I think the old impl
505-
// served as an implicit "flatten", and we don't want to introduce another level of nesting.
506-
Ok(Self {
507-
id: NullStr::<{ Self::MAX_ID_LENGTH }>::deserialize::<D>(
508-
deserializer,
509-
)?,
510-
})
511-
}
512-
}
513-
514494
impl core::fmt::Display for SpComponent {
515495
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
516496
self.id.fmt(f)
@@ -638,42 +618,15 @@ impl TryFrom<&str> for SpComponent {
638618
}
639619
}
640620

641-
// -----
642-
643621
/// Identifier for a single power rail.
644-
#[derive(Clone, Copy, PartialEq, Eq, Hash, SerializedSize)]
622+
#[derive(
623+
Clone, Copy, PartialEq, Eq, Hash, SerializedSize, Serialize, Deserialize,
624+
)]
625+
#[serde(transparent)]
645626
pub struct PowerRailName {
646627
name: nullstr::NullStr<{ Self::MAX_NAME_LENGTH }>,
647628
}
648629

649-
impl Serialize for PowerRailName {
650-
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
651-
where
652-
S: serde::Serializer,
653-
{
654-
// TODO(AJM): I don't think we can just derive deserialize here because I think the old impl
655-
// served as an implicit "flatten", and we don't want to introduce another level of nesting.
656-
nullstr::NullStr::<{ Self::MAX_NAME_LENGTH }>::serialize(
657-
&self.name, serializer,
658-
)
659-
}
660-
}
661-
662-
impl<'de> Deserialize<'de> for PowerRailName {
663-
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
664-
where
665-
D: serde::Deserializer<'de>,
666-
{
667-
// TODO(AJM): I don't think we can just derive deserialize here because I think the old impl
668-
// served as an implicit "flatten", and we don't want to introduce another level of nesting.
669-
Ok(Self {
670-
name: NullStr::<{ Self::MAX_NAME_LENGTH }>::deserialize::<D>(
671-
deserializer,
672-
)?,
673-
})
674-
}
675-
}
676-
677630
impl core::fmt::Display for PowerRailName {
678631
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
679632
self.name.fmt(f)
@@ -701,7 +654,7 @@ impl PowerRailName {
701654
/// This function should only be used in const contexts when the caller
702655
/// knows the component is valid (e.g., one of this type's associated
703656
/// constants); for component names parsed or constructed at runtime, prefer
704-
/// [`SpComponent::as_str()`] which performs runtime validation.
657+
/// [`PowerRailName::as_str()`] which performs runtime validation.
705658
#[inline]
706659
pub const fn const_as_str(&self) -> &str {
707660
self.name.const_as_str()
@@ -730,8 +683,6 @@ impl fmt::Debug for PowerRailName {
730683
}
731684
}
732685

733-
// -----
734-
735686
/// Minimum guaranteed space for trailing data in a single packet.
736687
///
737688
/// Depending on the [`Message`] payload, there may be more space for trailing
@@ -850,4 +801,33 @@ mod tests {
850801
(component, &[] as &[u8])
851802
);
852803
}
804+
805+
#[test]
806+
fn test_human_readable_power_rail() {
807+
let rail = const { PowerRailName::from_const("V0P96_NIC_VDD_A0HP") };
808+
let expected_value =
809+
serde_json::Value::String("V0P96_NIC_VDD_A0HP".to_string());
810+
811+
assert_eq!(serde_json::to_value(rail).unwrap(), expected_value);
812+
assert_eq!(
813+
serde_json::from_value::<PowerRailName>(expected_value).unwrap(),
814+
rail
815+
);
816+
}
817+
818+
#[test]
819+
fn test_non_human_readable_power_rail() {
820+
let rail = const { PowerRailName::from_const("V0P96_NIC_VDD_A0HP") };
821+
let expected_value = rail.name;
822+
823+
let mut out = [0; PowerRailName::MAX_SIZE];
824+
let n = hubpack::serialize(&mut out, &rail).unwrap();
825+
assert_eq!(&out[..n], expected_value.contents());
826+
827+
assert_eq!(
828+
hubpack::deserialize::<PowerRailName>(expected_value.contents())
829+
.unwrap(),
830+
(rail, &[] as &[u8])
831+
);
832+
}
853833
}

0 commit comments

Comments
 (0)