feat(domain): add Message constructor, accessors, and builder
This commit is contained in:
@@ -1,9 +0,0 @@
|
|||||||
use types::bounded::CapSlot;
|
|
||||||
|
|
||||||
pub const MAX_MESSAGE_WORDS: usize = 4;
|
|
||||||
pub const MAX_CAP_TRANSFERS: usize = 4;
|
|
||||||
|
|
||||||
pub struct Message {
|
|
||||||
words: [usize; MAX_MESSAGE_WORDS],
|
|
||||||
caps: [Option<CapSlot>; MAX_CAP_TRANSFERS],
|
|
||||||
}
|
|
||||||
76
crates/domain/src/message/mod.rs
Normal file
76
crates/domain/src/message/mod.rs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
use types::bounded::CapSlot;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "tests.rs"]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
pub const MAX_MESSAGE_WORDS: usize = 4;
|
||||||
|
pub const MAX_CAP_TRANSFERS: usize = 4;
|
||||||
|
|
||||||
|
pub struct Message {
|
||||||
|
words: [usize; MAX_MESSAGE_WORDS],
|
||||||
|
caps: [Option<CapSlot>; MAX_CAP_TRANSFERS],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
words: [0; MAX_MESSAGE_WORDS],
|
||||||
|
caps: [None; MAX_CAP_TRANSFERS],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_words(words: [usize; MAX_MESSAGE_WORDS]) -> Self {
|
||||||
|
Self {
|
||||||
|
words,
|
||||||
|
caps: [None; MAX_CAP_TRANSFERS],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn words(&self) -> &[usize; MAX_MESSAGE_WORDS] {
|
||||||
|
&self.words
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn word(&self, index: usize) -> usize {
|
||||||
|
self.words[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn caps(&self) -> &[Option<CapSlot>; MAX_CAP_TRANSFERS] {
|
||||||
|
&self.caps
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cap(&self, index: usize) -> Option<CapSlot> {
|
||||||
|
self.caps[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builder() -> MessageBuilder {
|
||||||
|
MessageBuilder {
|
||||||
|
message: Message::empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MessageBuilder {
|
||||||
|
message: Message,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MessageBuilder {
|
||||||
|
pub fn word(mut self, index: usize, value: usize) -> Self {
|
||||||
|
self.message.words[index] = value;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn words(mut self, words: [usize; MAX_MESSAGE_WORDS]) -> Self {
|
||||||
|
self.message.words = words;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cap(mut self, index: usize, slot: CapSlot) -> Self {
|
||||||
|
self.message.caps[index] = Some(slot);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Message {
|
||||||
|
self.message
|
||||||
|
}
|
||||||
|
}
|
||||||
86
crates/domain/src/message/tests.rs
Normal file
86
crates/domain/src/message/tests.rs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
use super::*;
|
||||||
|
use types::bounded::CapSlot;
|
||||||
|
|
||||||
|
fn slot(n: u8) -> CapSlot {
|
||||||
|
CapSlot::new(n).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Construction ---
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_message_has_zeroed_words_and_no_caps() {
|
||||||
|
let msg = Message::empty();
|
||||||
|
assert_eq!(msg.words(), &[0; MAX_MESSAGE_WORDS]);
|
||||||
|
for i in 0..MAX_CAP_TRANSFERS {
|
||||||
|
assert!(msg.cap(i).is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_words_sets_words_and_no_caps() {
|
||||||
|
let msg = Message::from_words([10, 20, 30, 40]);
|
||||||
|
assert_eq!(msg.word(0), 10);
|
||||||
|
assert_eq!(msg.word(1), 20);
|
||||||
|
assert_eq!(msg.word(2), 30);
|
||||||
|
assert_eq!(msg.word(3), 40);
|
||||||
|
assert!(msg.cap(0).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Accessors ---
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn words_returns_full_array() {
|
||||||
|
let msg = Message::from_words([1, 2, 3, 4]);
|
||||||
|
assert_eq!(msg.words(), &[1, 2, 3, 4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn caps_returns_full_array() {
|
||||||
|
let msg = Message::empty();
|
||||||
|
assert_eq!(msg.caps(), &[None; MAX_CAP_TRANSFERS]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Builder ---
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builder_sets_individual_words() {
|
||||||
|
let msg = Message::builder()
|
||||||
|
.word(0, 42)
|
||||||
|
.word(2, 99)
|
||||||
|
.build();
|
||||||
|
assert_eq!(msg.word(0), 42);
|
||||||
|
assert_eq!(msg.word(1), 0);
|
||||||
|
assert_eq!(msg.word(2), 99);
|
||||||
|
assert_eq!(msg.word(3), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builder_sets_caps() {
|
||||||
|
let msg = Message::builder()
|
||||||
|
.cap(0, slot(5))
|
||||||
|
.cap(1, slot(10))
|
||||||
|
.build();
|
||||||
|
assert_eq!(msg.cap(0), Some(slot(5)));
|
||||||
|
assert_eq!(msg.cap(1), Some(slot(10)));
|
||||||
|
assert!(msg.cap(2).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builder_sets_words_and_caps_together() {
|
||||||
|
let msg = Message::builder()
|
||||||
|
.word(0, 100)
|
||||||
|
.word(1, 200)
|
||||||
|
.cap(0, slot(3))
|
||||||
|
.build();
|
||||||
|
assert_eq!(msg.word(0), 100);
|
||||||
|
assert_eq!(msg.word(1), 200);
|
||||||
|
assert_eq!(msg.cap(0), Some(slot(3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builder_with_all_words() {
|
||||||
|
let msg = Message::builder()
|
||||||
|
.words([11, 22, 33, 44])
|
||||||
|
.build();
|
||||||
|
assert_eq!(msg.words(), &[11, 22, 33, 44]);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user