1use crate::error::{require, Error, Rule};
4use crate::path::ObjectPath;
5use crate::sequence::MAX_BOUNDED_SLOT;
6use crate::value::Slot;
7use crate::wire::{
8 decode_frame, decode_frame_value, get_blob, put_blob, wire_struct, Decoder, Encoder, Wire,
9};
10use coven_foundation::id_source::{DeviceId, StoreId};
11use std::collections::BTreeSet;
12
13#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct OriginalSlot {
16 pub slot: Slot,
18 pub object: Vec<u8>,
20}
21impl OriginalSlot {
22 pub fn path(&self, store: StoreId) -> ObjectPath {
24 ObjectPath::slot(store, self.slot.into())
25 }
26}
27impl Wire for OriginalSlot {
28 fn put(&self, out: &mut Encoder) -> Result<(), Error> {
29 self.slot.put(out)?;
30 put_blob(&self.object, out)
31 }
32 fn get(input: &mut Decoder<'_>) -> Result<Self, Error> {
33 Ok(Self { slot: Wire::get(input)?, object: get_blob(input)? })
34 }
35}
36impl OriginalSlot {
37 pub fn validate_kind(&self, kinds: &[u8]) -> Result<(), Error> {
41 crate::error::bound(self.object.len(), MAX_BOUNDED_SLOT, "retained slot")?;
42 let object = crate::sealed_slot::BoundedSlot::decode(&self.object)?;
43 require(kinds.contains(&object.prefix.kind.tag()), "retained slot kind", Rule::Kind)
44 }
45}
46
47#[derive(Clone, Debug, PartialEq, Eq)]
49pub struct FloorHeader {
50 pub author: DeviceId,
52 pub at: u64,
54 pub first: Slot,
56 pub snapshots: Vec<Slot>,
58}
59wire_struct!(FloorHeader, author, at, first, snapshots);
60impl FloorHeader {
61 fn validate(&self) -> Result<(), Error> {
62 require(!self.snapshots.is_empty(), "floor snapshots", Rule::Required)?;
63 require(
64 self.first.get() - 1 <= self.at
65 && self.snapshots.iter().all(|slot| slot.get() <= self.at),
66 "floor coverage",
67 Rule::Coverage,
68 )?;
69 let unique: BTreeSet<_> = self.snapshots.iter().collect();
70 require(unique.len() == self.snapshots.len(), "floor announcements", Rule::Order)
71 }
72 pub fn encode(&self) -> Result<Vec<u8>, Error> {
74 self.validate()?;
75 crate::encode_frame(crate::kinds::FLOOR_HEADER, self)
76 }
77 pub fn decode(bytes: &[u8]) -> Result<Self, Error> {
79 let header: Self = decode_frame_value(bytes, crate::kinds::FLOOR_HEADER, "floor header")?;
80 header.validate()?;
81 Ok(header)
82 }
83}
84
85pub struct FloorFrames {
87 header: FloorHeader,
88 next: usize,
89 ended: bool,
90}
91impl FloorFrames {
92 pub fn start(header: FloorHeader) -> Result<(Self, Vec<u8>), Error> {
94 let frame = header.encode()?;
95 Ok((Self { header, next: 0, ended: false }, frame))
96 }
97 pub fn decode_header(bytes: &[u8], first: Slot) -> Result<Self, Error> {
99 let header = FloorHeader::decode(bytes)?;
100 require(header.first == first, "floor first", Rule::Coverage)?;
101 Ok(Self { header, next: 0, ended: false })
102 }
103 pub fn header(&self) -> &FloorHeader {
105 &self.header
106 }
107 fn accept(&mut self, slot: &OriginalSlot) -> Result<(), Error> {
108 slot.validate_kind(&[3])?;
109 require(
110 !self.ended && self.header.snapshots.get(self.next) == Some(&slot.slot),
111 "floor announcement order",
112 Rule::Order,
113 )?;
114 self.next += 1;
115 Ok(())
116 }
117 pub fn announcement(&mut self, slot: &OriginalSlot) -> Result<Vec<u8>, Error> {
119 let bytes = crate::encode_frame(crate::kinds::SNAPSHOT_RECORD, slot)?;
120 self.accept(slot)?;
121 Ok(bytes)
122 }
123 pub fn end(&mut self) -> Result<Vec<u8>, Error> {
125 require(
126 !self.ended && self.next == self.header.snapshots.len(),
127 "floor end",
128 Rule::SnapshotSequence,
129 )?;
130 self.ended = true;
131 crate::encode_frame_with(crate::kinds::SNAPSHOT_END, |_| Ok(()))
132 }
133 pub fn frame(&mut self, bytes: &[u8]) -> Result<Option<OriginalSlot>, Error> {
135 let (kind, mut input) = decode_frame(bytes)?;
136 if kind == crate::kinds::SNAPSHOT_END {
137 input.finish()?;
138 require(
139 !self.ended && self.next == self.header.snapshots.len(),
140 "floor end",
141 Rule::SnapshotSequence,
142 )?;
143 self.ended = true;
144 return Ok(None);
145 }
146 require(kind == crate::kinds::SNAPSHOT_RECORD, "floor announcement", Rule::Kind)?;
147 let slot = OriginalSlot::get(&mut input)?;
148 input.finish()?;
149 self.accept(&slot)?;
150 Ok(Some(slot))
151 }
152 pub fn finish(&self) -> Result<(), Error> {
154 if self.ended {
155 Ok(())
156 } else {
157 Err(Error::Truncated)
158 }
159 }
160}
161
162#[cfg(test)]
163#[path = "floor_tests.rs"]
164mod tests;