1use std::fmt;
12use std::future::poll_fn;
13use std::sync::Arc;
14use std::task::Poll;
15
16use crate::node::{Inbox, Wait};
17use crate::schema::{EventSchema, SchemaId};
18use crate::stream::Item;
19use crate::time::{Tick, TickRange};
20
21pub const MAX_CHANNELS: u8 = 64;
23
24pub const LOGIC_SAMPLES: SchemaId = SchemaId::new("logic.samples", 1);
26
27impl EventSchema for Arc<LogicBlock> {
28 const SCHEMA: SchemaId = LOGIC_SAMPLES;
29}
30
31#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
33pub struct ChannelMask(pub u64);
34
35impl ChannelMask {
36 pub const EMPTY: ChannelMask = ChannelMask(0);
38
39 pub const fn one(channel: u8) -> Self {
41 ChannelMask(1u64 << (channel & 63))
42 }
43
44 pub const fn with(self, channel: u8) -> Self {
46 ChannelMask(self.0 | (1u64 << (channel & 63)))
47 }
48
49 pub const fn has(self, channel: u8) -> bool {
51 self.0 & (1u64 << (channel & 63)) != 0
52 }
53
54 pub const fn is_empty(self) -> bool {
56 self.0 == 0
57 }
58
59 pub fn of(channels: impl IntoIterator<Item = Option<u8>>) -> Self {
61 channels
62 .into_iter()
63 .flatten()
64 .fold(ChannelMask::EMPTY, ChannelMask::with)
65 }
66
67 pub fn iter(self) -> impl Iterator<Item = u8> {
69 let mut bits = self.0;
70 std::iter::from_fn(move || {
71 if bits == 0 {
72 return None;
73 }
74 let channel = bits.trailing_zeros() as u8;
75 bits &= bits - 1;
76 Some(channel)
77 })
78 }
79}
80
81#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
83pub struct Levels(pub u64);
84
85impl Levels {
86 pub const fn high(self, channel: u8) -> bool {
88 self.0 & (1u64 << (channel & 63)) != 0
89 }
90
91 pub const fn changed_from(self, other: Levels, mask: ChannelMask) -> ChannelMask {
93 ChannelMask((self.0 ^ other.0) & mask.0)
94 }
95}
96
97#[derive(Clone, PartialEq, Eq)]
100pub struct LogicBlock {
101 start: Tick,
102 len: u64,
103 channels: u8,
104 stride: usize,
106 words: Vec<u64>,
108}
109
110#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
112pub enum BlockError {
113 #[error("a block holds at least one sample")]
115 Empty,
116 #[error("{0} channels: a block holds at most {MAX_CHANNELS}")]
118 TooManyChannels(u8),
119 #[error("{found} words given for {channels} channels of {len} samples ({expected} needed)")]
121 WrongSize {
122 channels: u8,
124 len: u64,
126 expected: usize,
128 found: usize,
130 },
131}
132
133impl LogicBlock {
134 pub fn from_words(
137 start: Tick,
138 len: u64,
139 channels: u8,
140 mut words: Vec<u64>,
141 ) -> Result<Self, BlockError> {
142 if len == 0 {
143 return Err(BlockError::Empty);
144 }
145 if channels > MAX_CHANNELS {
146 return Err(BlockError::TooManyChannels(channels));
147 }
148 let stride = usize::try_from(len.div_ceil(64)).map_err(|_| BlockError::WrongSize {
149 channels,
150 len,
151 expected: usize::MAX,
152 found: words.len(),
153 })?;
154 let expected = stride * usize::from(channels);
155 if words.len() != expected {
156 return Err(BlockError::WrongSize {
157 channels,
158 len,
159 expected,
160 found: words.len(),
161 });
162 }
163 let valid = len % 64;
165 if valid != 0 {
166 let keep = (1u64 << valid) - 1;
167 for channel in 0..usize::from(channels) {
168 words[channel * stride + stride - 1] &= keep;
169 }
170 }
171 Ok(Self {
172 start,
173 len,
174 channels,
175 stride,
176 words,
177 })
178 }
179
180 pub fn from_interleaved(start: Tick, channels: u8, bytes: &[u8]) -> Result<Self, BlockError> {
183 if channels > MAX_CHANNELS {
184 return Err(BlockError::TooManyChannels(channels));
185 }
186 let unit = usize::from(channels).div_ceil(8).max(1);
187 let len = bytes.len() / unit;
188 if len == 0 {
189 return Err(BlockError::Empty);
190 }
191 let stride = len.div_ceil(64);
192 let channels_len = usize::from(channels);
193 let mut words = vec![0u64; stride * channels_len];
194 for (index, tile) in bytes[..len * unit].chunks(64 * unit).enumerate() {
198 for group in 0..channels_len.div_ceil(8) {
199 let mut rows = [0u64; 8];
200 for (row, samples) in tile.chunks(8 * unit).enumerate() {
201 rows[row] = if unit == 1 && samples.len() == 8 {
202 u64::from_le_bytes([
203 samples[0], samples[1], samples[2], samples[3], samples[4], samples[5],
204 samples[6], samples[7],
205 ])
206 } else {
207 samples
208 .chunks_exact(unit)
209 .enumerate()
210 .fold(0u64, |row, (sample, bytes)| {
211 row | u64::from(bytes[group]) << (8 * sample)
212 })
213 };
214 }
215 let lanes = transpose_64x8(rows);
216 let first = 8 * group;
217 for channel in first..(first + 8).min(channels_len) {
218 words[channel * stride + index] = lanes[channel - first];
219 }
220 }
221 }
222 Ok(Self {
223 start,
224 len: len as u64,
225 channels,
226 stride,
227 words,
228 })
229 }
230
231 pub fn start(&self) -> Tick {
233 self.start
234 }
235
236 pub fn len(&self) -> u64 {
238 self.len
239 }
240
241 pub fn is_empty(&self) -> bool {
243 self.len == 0
244 }
245
246 pub fn end(&self) -> Tick {
248 self.start.offset(self.len)
249 }
250
251 pub fn range(&self) -> TickRange {
253 TickRange::new(self.start, self.end())
254 }
255
256 pub fn channels(&self) -> u8 {
258 self.channels
259 }
260
261 pub fn contains(&self, tick: Tick) -> bool {
263 self.range().contains(tick)
264 }
265
266 pub fn words(&self, channel: u8) -> &[u64] {
268 let channel = usize::from(channel);
269 &self.words[channel * self.stride..(channel + 1) * self.stride]
270 }
271
272 fn word(&self, channel: u8, index: usize) -> u64 {
273 self.words[usize::from(channel) * self.stride + index]
274 }
275
276 pub fn level(&self, channel: u8, tick: Tick) -> Option<bool> {
278 if channel >= self.channels || !self.contains(tick) {
279 return None;
280 }
281 let offset = self.start.until(tick);
282 let word = self.word(channel, (offset / 64) as usize);
283 Some(word >> (offset % 64) & 1 != 0)
284 }
285
286 pub fn levels(&self, tick: Tick) -> Option<Levels> {
288 if !self.contains(tick) {
289 return None;
290 }
291 let offset = self.start.until(tick);
292 let (index, bit) = ((offset / 64) as usize, offset % 64);
293 let mut levels = 0u64;
295 for channel in 0..self.channels {
296 levels |= (self.word(channel, index) >> bit & 1) << channel;
297 }
298 Some(Levels(levels))
299 }
300
301 pub fn rebased(&self, start: Tick) -> LogicBlock {
303 LogicBlock {
304 start,
305 ..self.clone()
306 }
307 }
308
309 pub fn slice(&self, range: TickRange) -> Option<LogicBlock> {
312 if range.is_empty() || range.start < self.start || range.end > self.end() {
313 return None;
314 }
315 let mut builder = LogicBlockBuilder::new(range.start, self.channels);
316 let mut tick = range.start;
317 while tick < range.end {
318 builder.push(self.levels(tick)?);
319 tick = tick.next();
320 }
321 builder.finish().ok()
322 }
323
324 pub fn next_change(
328 &self,
329 mask: ChannelMask,
330 from: Tick,
331 prev: Levels,
332 ) -> Option<(Tick, ChannelMask)> {
333 if !self.contains(from) {
334 return None;
335 }
336 let present = if self.channels >= MAX_CHANNELS {
338 u64::MAX
339 } else {
340 (1u64 << self.channels) - 1
341 };
342 let watched = mask.0 & present;
343 if watched == 0 {
344 return None;
345 }
346 let first = self.start.until(from) as usize;
347 let (first_word, shift) = (first / 64, first % 64);
348 let (stride, words) = (self.stride, &self.words);
349 let edges = |channel: usize, index: usize| -> u64 {
353 let current = words[channel * stride + index];
354 let before = if index == first_word {
355 ((current << 1) & !(1u64 << shift)) | (u64::from(prev.high(channel as u8)) << shift)
356 } else {
357 (current << 1) | (words[channel * stride + index - 1] >> 63)
358 };
359 current ^ before
360 };
361 let last_word = stride - 1;
362 let valid_in_last = self.len - 64 * last_word as u64;
363 for index in first_word..stride {
364 let mut diff = 0u64;
365 let mut bits = watched;
366 while bits != 0 {
367 let channel = bits.trailing_zeros() as usize;
368 bits &= bits - 1;
369 diff |= edges(channel, index);
370 }
371 if index == first_word {
372 diff &= u64::MAX << shift;
373 }
374 if index == last_word && valid_in_last < 64 {
375 diff &= (1u64 << valid_in_last) - 1;
376 }
377 if diff == 0 {
378 continue;
379 }
380 let bit = diff.trailing_zeros();
381 let tick = self.start.offset(64 * index as u64 + u64::from(bit));
382 let mut changed = 0u64;
385 let mut bits = watched;
386 while bits != 0 {
387 let channel = bits.trailing_zeros() as usize;
388 bits &= bits - 1;
389 changed |= (edges(channel, index) >> bit & 1) << channel;
390 }
391 return Some((tick, ChannelMask(changed)));
392 }
393 None
394 }
395}
396
397fn transpose_8x8(mut matrix: u64) -> u64 {
400 let swap = (matrix ^ (matrix >> 7)) & 0x00aa_00aa_00aa_00aa;
401 matrix ^= swap ^ (swap << 7);
402 let swap = (matrix ^ (matrix >> 14)) & 0x0000_cccc_0000_cccc;
403 matrix ^= swap ^ (swap << 14);
404 let swap = (matrix ^ (matrix >> 28)) & 0x0000_0000_f0f0_f0f0;
405 matrix ^ swap ^ (swap << 28)
406}
407
408fn transpose_64x8(rows: [u64; 8]) -> [u64; 8] {
413 let mut t = rows.map(transpose_8x8);
414 for row in 0..4 {
415 let (a, b) = (t[row], t[row + 4]);
416 t[row] = (a & 0x0000_0000_ffff_ffff) | (b << 32);
417 t[row + 4] = (a >> 32) | (b & 0xffff_ffff_0000_0000);
418 }
419 for row in [0, 1, 4, 5] {
420 let (a, b) = (t[row], t[row + 2]);
421 t[row] = (a & 0x0000_ffff_0000_ffff) | ((b & 0x0000_ffff_0000_ffff) << 16);
422 t[row + 2] = ((a & 0xffff_0000_ffff_0000) >> 16) | (b & 0xffff_0000_ffff_0000);
423 }
424 for row in [0, 2, 4, 6] {
425 let (a, b) = (t[row], t[row + 1]);
426 t[row] = (a & 0x00ff_00ff_00ff_00ff) | ((b & 0x00ff_00ff_00ff_00ff) << 8);
427 t[row + 1] = ((a & 0xff00_ff00_ff00_ff00) >> 8) | (b & 0xff00_ff00_ff00_ff00);
428 }
429 t
430}
431
432impl fmt::Debug for LogicBlock {
433 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
434 f.debug_struct("LogicBlock")
435 .field("start", &self.start)
436 .field("len", &self.len)
437 .field("channels", &self.channels)
438 .finish_non_exhaustive()
439 }
440}
441
442#[derive(Clone, Debug)]
444pub struct LogicBlockBuilder {
445 start: Tick,
446 channels: u8,
447 len: u64,
448 lanes: Vec<Vec<u64>>,
450}
451
452impl LogicBlockBuilder {
453 pub fn new(start: Tick, channels: u8) -> Self {
455 let channels = channels.min(MAX_CHANNELS);
456 Self {
457 start,
458 channels,
459 len: 0,
460 lanes: vec![Vec::new(); usize::from(channels)],
461 }
462 }
463
464 pub fn len(&self) -> u64 {
466 self.len
467 }
468
469 pub fn is_empty(&self) -> bool {
471 self.len == 0
472 }
473
474 pub fn next_tick(&self) -> Tick {
476 self.start.offset(self.len)
477 }
478
479 pub fn push(&mut self, levels: Levels) {
481 let bit = self.len % 64;
482 if bit == 0 {
483 for lane in &mut self.lanes {
484 lane.push(0);
485 }
486 }
487 for (channel, lane) in self.lanes.iter_mut().enumerate() {
488 if levels.0 >> channel & 1 != 0
489 && let Some(word) = lane.last_mut()
490 {
491 *word |= 1u64 << bit;
492 }
493 }
494 self.len += 1;
495 }
496
497 pub fn push_repeated(&mut self, levels: Levels, count: u64) {
499 for _ in 0..count {
500 self.push(levels);
501 }
502 }
503
504 pub fn finish(self) -> Result<LogicBlock, BlockError> {
506 let stride = self.len.div_ceil(64) as usize;
507 let mut words = Vec::with_capacity(stride * usize::from(self.channels));
508 for lane in self.lanes {
509 words.extend(lane);
510 }
511 LogicBlock::from_words(self.start, self.len, self.channels, words)
512 }
513}
514
515#[derive(Clone, Debug)]
517pub enum SignalItem {
518 Data(Arc<LogicBlock>),
520 Progress(Tick),
522 Gap(TickRange),
524 End(Tick),
526}
527
528#[derive(Clone, Copy, Debug, PartialEq, Eq)]
530pub enum Change {
531 At {
533 tick: Tick,
535 changed: ChannelMask,
537 levels: Levels,
539 },
540 Quiet(Tick),
543 Gap(TickRange),
545 Progress(Tick),
548 End(Tick),
550}
551
552#[derive(Clone, Copy, Debug, PartialEq, Eq)]
554pub enum Sample {
555 At {
557 tick: Tick,
559 levels: Levels,
561 },
562 Gap(TickRange),
564 Progress(Tick),
566 End(Tick),
568}
569
570pub struct SignalCursor {
579 inbox: Inbox<Arc<LogicBlock>>,
580 block: Option<Arc<LogicBlock>>,
582 pos: Tick,
584 prev: Levels,
586 prev_tick: Option<Tick>,
588 exhausted: Option<Tick>,
590}
591
592impl fmt::Debug for SignalCursor {
593 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
594 f.debug_struct("SignalCursor")
595 .field("pos", &self.pos)
596 .field("prev", &self.prev)
597 .field("prev_tick", &self.prev_tick)
598 .finish_non_exhaustive()
599 }
600}
601
602enum Found {
604 Change(Tick, ChannelMask, Levels),
605 Quiet(Tick),
606 Exhausted,
608}
609
610impl crate::node::Readable for SignalCursor {
611 fn poll_ready(&self) -> Poll<()> {
612 if self.block.is_some() {
613 return Poll::Ready(());
614 }
615 self.inbox.poll_ready()
616 }
617}
618
619impl SignalCursor {
620 pub(crate) fn new(inbox: Inbox<Arc<LogicBlock>>) -> Self {
621 Self {
622 inbox,
623 block: None,
624 pos: Tick::ZERO,
625 prev: Levels(0),
626 prev_tick: None,
627 exhausted: None,
628 }
629 }
630
631 pub fn position(&self) -> Tick {
633 self.pos
634 }
635
636 pub fn seek(&mut self, tick: Tick) {
639 if tick > self.pos {
640 self.pos = tick;
641 }
642 if let Some(block) = self.block.take() {
646 if block.end() <= self.pos {
647 self.release(&block);
648 } else {
649 self.block = Some(block);
650 }
651 }
652 while self.block.is_none() {
655 let passed = match self.inbox.poll_peek() {
656 Poll::Ready(item) => match &*item {
657 Item::Event(event) if event.payload.end() <= self.pos => {
658 Some(Some(Arc::clone(&event.payload)))
659 }
660 Item::Progress(tick) if *tick <= self.pos => Some(None),
661 _ => None,
662 },
663 Poll::Pending => None,
664 };
665 let Some(block) = passed else {
666 break;
667 };
668 self.inbox.advance();
669 if let Some(block) = block {
670 self.release(&block);
671 }
672 }
673 }
674
675 fn release(&mut self, block: &LogicBlock) {
677 let last = Tick(block.end().0 - 1);
678 self.prev = block.levels(last).unwrap_or_default();
679 self.prev_tick = Some(last);
680 self.pos = self.pos.max(block.end());
681 self.exhausted = Some(block.end());
682 self.block = None;
683 }
684
685 fn poll_source(&mut self) -> Poll<Option<Item<Arc<LogicBlock>>>> {
688 let taken = match self.inbox.poll_peek() {
689 Poll::Pending => return Poll::Pending,
690 Poll::Ready(item) => match &*item {
691 Item::Event(event) => {
692 self.block = Some(Arc::clone(&event.payload));
693 self.pos = self.pos.max(event.payload.start());
696 None
697 }
698 Item::Gap(range) => Some(Item::Gap(*range)),
699 Item::Progress(tick) => Some(Item::Progress(*tick)),
700 Item::End(tick) => Some(Item::End(*tick)),
701 },
702 };
703 if !matches!(taken, Some(Item::End(_))) {
705 self.inbox.advance();
706 }
707 if let Some(Item::Gap(range)) = taken {
708 self.pos = self.pos.max(range.end);
709 self.prev_tick = None;
710 }
711 self.exhausted = None;
712 Poll::Ready(taken)
713 }
714
715 fn scan(&mut self, block: &LogicBlock, mask: ChannelMask, until: Option<Tick>) -> Found {
717 if block.end() <= self.pos {
718 self.release(block);
719 return Found::Exhausted;
720 }
721 let limit = until.map_or(block.end(), |until| until.min(block.end()));
722 if limit <= self.pos {
723 return Found::Quiet(self.pos);
724 }
725 let before = Tick(self.pos.0.saturating_sub(1));
726 let (from, prev) = if self.prev_tick == Some(before) && self.pos > Tick::ZERO {
727 (self.pos, self.prev)
728 } else if self.pos > block.start() {
729 (self.pos, block.levels(before).unwrap_or_default())
730 } else {
731 (self.pos.next(), block.levels(self.pos).unwrap_or_default())
733 };
734 if from < limit
735 && let Some((tick, changed)) = block.next_change(mask, from, prev)
736 && tick < limit
737 {
738 let levels = block.levels(tick).unwrap_or_default();
739 self.prev = levels;
740 self.prev_tick = Some(tick);
741 self.pos = tick.next();
742 return Found::Change(tick, changed, levels);
743 }
744 if limit < block.end() {
745 let last = Tick(limit.0 - 1);
746 self.prev = block.levels(last).unwrap_or_default();
747 self.prev_tick = Some(last);
748 self.pos = limit;
749 return Found::Quiet(limit);
750 }
751 self.release(block);
752 Found::Exhausted
753 }
754
755 fn poll_change(&mut self, mask: ChannelMask, until: Option<Tick>) -> Poll<Change> {
756 let cx = self.inbox.cx().clone();
757 if !cx.has_budget() {
758 cx.wait(Wait::Budget);
759 return Poll::Pending;
760 }
761 loop {
762 if let Some(block) = self.block.take() {
765 let found = self.scan(&block, mask, until);
766 if !matches!(found, Found::Exhausted) {
767 self.block = Some(block);
768 }
769 match found {
770 Found::Change(tick, changed, levels) => {
771 cx.spend();
772 return Poll::Ready(Change::At {
773 tick,
774 changed,
775 levels,
776 });
777 }
778 Found::Quiet(tick) => {
779 cx.spend();
780 return Poll::Ready(Change::Quiet(tick));
781 }
782 Found::Exhausted => continue,
784 }
785 } else if let Some(until) = until
786 && until <= self.pos
787 {
788 cx.spend();
789 return Poll::Ready(Change::Quiet(self.pos));
790 }
791 match self.poll_source() {
792 Poll::Pending => {
793 if let Some(end) = self.exhausted.take() {
794 cx.spend();
795 return Poll::Ready(Change::Progress(end));
796 }
797 return Poll::Pending;
798 }
799 Poll::Ready(None) => continue,
800 Poll::Ready(Some(Item::Gap(range))) => {
801 cx.spend();
802 return Poll::Ready(Change::Gap(range));
803 }
804 Poll::Ready(Some(Item::Progress(tick))) => {
805 cx.spend();
806 return Poll::Ready(Change::Progress(tick));
807 }
808 Poll::Ready(Some(Item::End(tick))) => {
809 cx.spend();
810 return Poll::Ready(Change::End(tick));
811 }
812 Poll::Ready(Some(Item::Event(_))) => unreachable!("blocks are kept, not returned"),
813 }
814 }
815 }
816
817 fn poll_sample(&mut self) -> Poll<Sample> {
818 let cx = self.inbox.cx().clone();
819 if !cx.has_budget() {
820 cx.wait(Wait::Budget);
821 return Poll::Pending;
822 }
823 loop {
824 if let Some(block) = self.block.take() {
825 if let Some(levels) = block.levels(self.pos) {
826 self.block = Some(block);
827 cx.spend();
828 return Poll::Ready(Sample::At {
829 tick: self.pos,
830 levels,
831 });
832 }
833 self.release(&block);
834 }
835 match self.poll_source() {
836 Poll::Pending => {
837 if let Some(end) = self.exhausted.take() {
838 cx.spend();
839 return Poll::Ready(Sample::Progress(end));
840 }
841 return Poll::Pending;
842 }
843 Poll::Ready(None) => continue,
844 Poll::Ready(Some(Item::Gap(range))) => {
845 cx.spend();
846 return Poll::Ready(Sample::Gap(range));
847 }
848 Poll::Ready(Some(Item::Progress(tick))) => {
849 cx.spend();
850 return Poll::Ready(Sample::Progress(tick));
851 }
852 Poll::Ready(Some(Item::End(tick))) => {
853 cx.spend();
854 return Poll::Ready(Sample::End(tick));
855 }
856 Poll::Ready(Some(Item::Event(_))) => unreachable!("blocks are kept, not returned"),
857 }
858 }
859 }
860
861 pub fn next_change(&mut self, mask: ChannelMask) -> impl Future<Output = Change> + '_ {
864 poll_fn(move |_| self.poll_change(mask, None))
865 }
866
867 pub fn next_change_before(
871 &mut self,
872 mask: ChannelMask,
873 until: Tick,
874 ) -> impl Future<Output = Change> + '_ {
875 poll_fn(move |_| self.poll_change(mask, Some(until)))
876 }
877
878 pub fn sample(&mut self) -> impl Future<Output = Sample> + '_ {
881 poll_fn(move |_| self.poll_sample())
882 }
883}
884
885#[cfg(test)]
886mod tests {
887 use super::*;
888
889 fn block(start: u64, samples: &[u64], channels: u8) -> LogicBlock {
890 let mut builder = LogicBlockBuilder::new(Tick(start), channels);
891 for levels in samples {
892 builder.push(Levels(*levels));
893 }
894 builder.finish().expect("a block")
895 }
896
897 #[test]
898 fn builder_packs_bits_per_channel() {
899 let block = block(10, &[0b01, 0b11, 0b10, 0b00], 2);
900 assert_eq!(block.len(), 4);
901 assert_eq!(block.end(), Tick(14));
902 assert_eq!(block.words(0), &[0b0011]);
903 assert_eq!(block.words(1), &[0b0110]);
904 assert_eq!(block.level(0, Tick(10)), Some(true));
905 assert_eq!(block.level(1, Tick(10)), Some(false));
906 assert_eq!(block.level(0, Tick(14)), None);
907 assert_eq!(block.levels(Tick(11)), Some(Levels(0b11)));
908 }
909
910 #[test]
911 fn interleaved_bytes_follow_the_export_layout() {
912 let block =
913 LogicBlock::from_interleaved(Tick(0), 12, &[0x01, 0x08, 0xff, 0x0f]).expect("a block");
914 assert_eq!(block.len(), 2);
915 assert_eq!(block.levels(Tick(0)), Some(Levels(0x801)));
916 assert_eq!(block.levels(Tick(1)), Some(Levels(0xfff)));
917 let four = LogicBlock::from_interleaved(Tick(5), 4, &[0x3, 0x0, 0xc]).expect("a block");
918 assert_eq!(four.len(), 3);
919 assert_eq!(four.levels(Tick(7)), Some(Levels(0xc)));
920 }
921
922 fn interleaved_by_sample(
924 start: Tick,
925 channels: u8,
926 bytes: &[u8],
927 ) -> Result<LogicBlock, BlockError> {
928 let unit = usize::from(channels).div_ceil(8).max(1);
929 let len = bytes.len() / unit;
930 let mut builder = LogicBlockBuilder::new(start, channels);
931 for sample in bytes.chunks_exact(unit).take(len) {
932 let mut levels = 0u64;
933 for (group, byte) in sample.iter().enumerate() {
934 levels |= u64::from(*byte) << (8 * group);
935 }
936 builder.push(Levels(levels));
937 }
938 builder.finish()
939 }
940
941 proptest::proptest! {
942 #[test]
943 fn interleaved_matches_the_sample_by_sample_build(
944 channels in 0u8..=64,
945 bytes in proptest::collection::vec(proptest::prelude::any::<u8>(), 0..1200),
946 ) {
947 let fast = LogicBlock::from_interleaved(Tick(3), channels, &bytes);
948 let slow = interleaved_by_sample(Tick(3), channels, &bytes);
949 proptest::prop_assert_eq!(fast, slow);
950 }
951 }
952
953 #[test]
954 fn transposes_eight_by_eight() {
955 assert_eq!(transpose_8x8(0xff), 0x0101_0101_0101_0101);
957 assert_eq!(transpose_8x8(0x0101_0101_0101_0101), 0xff);
958 let identity = (0..8).fold(0u64, |m, i| m | 1u64 << (9 * i));
959 assert_eq!(transpose_8x8(identity), identity);
960 assert_eq!(transpose_8x8(1 << (8 * 2 + 5)), 1 << (8 * 5 + 2));
962 }
963
964 #[test]
965 fn rejects_bad_blocks() {
966 assert_eq!(
967 LogicBlockBuilder::new(Tick(0), 1)
968 .finish()
969 .expect_err("fails"),
970 BlockError::Empty
971 );
972 assert!(matches!(
973 LogicBlock::from_words(Tick(0), 65, 1, vec![0]),
974 Err(BlockError::WrongSize {
975 expected: 2,
976 found: 1,
977 ..
978 })
979 ));
980 assert_eq!(
981 LogicBlock::from_words(Tick(0), 1, 65, vec![]).expect_err("fails"),
982 BlockError::TooManyChannels(65)
983 );
984 }
985
986 #[test]
987 fn finds_changes_within_and_across_words() {
988 let mut samples = vec![0u64; 100];
989 samples[3] = 1;
990 samples[4] = 1;
991 samples[64] = 2;
992 samples[99] = 3;
993 let block = block(0, &samples, 2);
994 let both = ChannelMask::one(0).with(1);
995 assert_eq!(
996 block.next_change(both, Tick(0), Levels(0)),
997 Some((Tick(3), ChannelMask::one(0)))
998 );
999 assert_eq!(
1000 block.next_change(both, Tick(4), Levels(1)),
1001 Some((Tick(5), ChannelMask::one(0)))
1002 );
1003 assert_eq!(
1004 block.next_change(both, Tick(6), Levels(0)),
1005 Some((Tick(64), ChannelMask::one(1)))
1006 );
1007 assert_eq!(
1008 block.next_change(ChannelMask::one(0), Tick(6), Levels(0)),
1009 Some((Tick(99), ChannelMask::one(0)))
1010 );
1011 assert_eq!(block.next_change(both, Tick(99), Levels(0b11)), None);
1012 assert_eq!(block.next_change(both, Tick(100), Levels(0)), None);
1013 assert_eq!(
1015 block.next_change(both, Tick(0), Levels(0b11)),
1016 Some((Tick(0), both))
1017 );
1018 }
1019
1020 #[test]
1021 fn padding_bits_are_no_change() {
1022 let block = block(0, &[1, 1, 1], 1);
1023 assert_eq!(
1024 block.next_change(ChannelMask::one(0), Tick(1), Levels(1)),
1025 None
1026 );
1027 }
1028
1029 #[test]
1030 fn slices_copy_the_samples() {
1031 let samples: Vec<u64> = (0..200).map(|i| i % 3).collect();
1032 let block = block(1000, &samples, 2);
1033 let slice = block
1034 .slice(TickRange::new(Tick(1063), Tick(1130)))
1035 .expect("a slice");
1036 assert_eq!(slice.start(), Tick(1063));
1037 assert_eq!(slice.len(), 67);
1038 for tick in 1063..1130 {
1039 assert_eq!(slice.levels(Tick(tick)), block.levels(Tick(tick)));
1040 }
1041 assert!(block.slice(TickRange::new(Tick(999), Tick(1001))).is_none());
1042 assert!(block.slice(TickRange::at(Tick(1001))).is_none());
1043 }
1044
1045 #[test]
1046 fn rebasing_moves_the_samples() {
1047 let block = block(10, &[1, 0, 1], 1);
1048 let moved = block.rebased(Tick(500));
1049 assert_eq!(moved.range(), TickRange::new(Tick(500), Tick(503)));
1050 assert_eq!(moved.level(0, Tick(502)), Some(true));
1051 assert_eq!(moved.words(0), block.words(0));
1052 }
1053
1054 use std::cell::RefCell;
1055 use std::future::Future;
1056 use std::pin::Pin;
1057 use std::rc::Rc;
1058 use std::task::{Context, Poll, Waker};
1059
1060 use crate::node::NodeCx;
1061 use crate::stream::{Broadcast, Event};
1062
1063 fn poll<F: Future>(future: Pin<&mut F>) -> Poll<F::Output> {
1064 future.poll(&mut Context::from_waker(Waker::noop()))
1065 }
1066
1067 fn cursor() -> (SignalCursor, Rc<RefCell<Broadcast<Arc<LogicBlock>>>>) {
1069 let queue = Rc::new(RefCell::new(Broadcast::new(16)));
1070 let cx = NodeCx::new();
1071 cx.refill(1_000);
1072 (SignalCursor::new(Inbox::new(Rc::clone(&queue), cx)), queue)
1073 }
1074
1075 fn push(queue: &Rc<RefCell<Broadcast<Arc<LogicBlock>>>>, block: LogicBlock) {
1076 let last = Tick(block.end().0 - 1);
1077 let item = Item::Event(Event {
1078 seq: 0,
1079 span: block.range(),
1080 settled: last,
1081 payload: Arc::new(block),
1082 });
1083 queue
1084 .borrow_mut()
1085 .try_push(item)
1086 .map_err(|_| ())
1087 .expect("fits");
1088 }
1089
1090 #[test]
1091 fn seeks_ahead_and_keeps_the_level_before_the_position() {
1092 let (mut cursor, queue) = cursor();
1093 let mut samples = vec![0u64; 100];
1095 samples.extend(std::iter::repeat_n(1u64, 60));
1096 let whole = block(0, &samples, 1);
1097 for start in (0..160).step_by(40) {
1098 push(
1099 &queue,
1100 whole
1101 .slice(TickRange::new(Tick(start), Tick(start + 40)))
1102 .expect("a slice"),
1103 );
1104 }
1105 cursor.seek(Tick(100));
1106 let change = poll(Box::pin(cursor.next_change(ChannelMask::one(0))).as_mut());
1108 assert_eq!(
1109 change,
1110 Poll::Ready(Change::At {
1111 tick: Tick(100),
1112 changed: ChannelMask::one(0),
1113 levels: Levels(1)
1114 })
1115 );
1116 cursor.seek(Tick(50));
1117 assert_eq!(cursor.position(), Tick(101), "a seek never moves back");
1118 cursor.seek(Tick(130));
1119 let sample = poll(Box::pin(cursor.sample()).as_mut());
1120 assert_eq!(
1121 sample,
1122 Poll::Ready(Sample::At {
1123 tick: Tick(130),
1124 levels: Levels(1)
1125 })
1126 );
1127 }
1128
1129 #[test]
1130 fn a_deadline_ends_the_wait_quietly() {
1131 let (mut cursor, queue) = cursor();
1132 let mut samples = vec![0u64; 50];
1134 for sample in &mut samples[30..] {
1135 *sample = 1;
1136 }
1137 push(&queue, block(0, &samples, 1));
1138 let until =
1139 poll(Box::pin(cursor.next_change_before(ChannelMask::one(0), Tick(20))).as_mut());
1140 assert_eq!(until, Poll::Ready(Change::Quiet(Tick(20))));
1141 assert_eq!(cursor.position(), Tick(20));
1142 let found =
1143 poll(Box::pin(cursor.next_change_before(ChannelMask::one(0), Tick(40))).as_mut());
1144 assert!(matches!(
1145 found,
1146 Poll::Ready(Change::At { tick: Tick(30), .. })
1147 ));
1148 let past =
1150 poll(Box::pin(cursor.next_change_before(ChannelMask::one(0), Tick(10))).as_mut());
1151 assert_eq!(past, Poll::Ready(Change::Quiet(Tick(31))));
1152 let pending =
1154 poll(Box::pin(cursor.next_change_before(ChannelMask::one(0), Tick(80))).as_mut());
1155 assert_eq!(
1156 pending,
1157 Poll::Ready(Change::Progress(Tick(50))),
1158 "the used-up block is announced"
1159 );
1160 let pending =
1161 poll(Box::pin(cursor.next_change_before(ChannelMask::one(0), Tick(80))).as_mut());
1162 assert_eq!(pending, Poll::Pending);
1163 push(&queue, block(50, &[1u64; 50], 1));
1164 let quiet =
1165 poll(Box::pin(cursor.next_change_before(ChannelMask::one(0), Tick(80))).as_mut());
1166 assert_eq!(quiet, Poll::Ready(Change::Quiet(Tick(80))));
1167 }
1168
1169 #[test]
1170 fn a_deadline_at_the_end_of_a_block_needs_no_next_block() {
1171 let (mut cursor, queue) = cursor();
1172 push(&queue, block(0, &[0u64; 50], 1));
1173 let quiet =
1174 poll(Box::pin(cursor.next_change_before(ChannelMask::one(0), Tick(50))).as_mut());
1175 assert_eq!(quiet, Poll::Ready(Change::Quiet(Tick(50))));
1176 assert_eq!(cursor.position(), Tick(50));
1177 assert_eq!(
1179 poll(Box::pin(cursor.next_change(ChannelMask::one(0))).as_mut()),
1180 Poll::Ready(Change::Progress(Tick(50)))
1181 );
1182 assert_eq!(
1183 poll(Box::pin(cursor.next_change(ChannelMask::one(0))).as_mut()),
1184 Poll::Pending
1185 );
1186 }
1187
1188 #[test]
1189 fn a_used_up_block_is_announced_once() {
1190 let (mut cursor, queue) = cursor();
1191 push(&queue, block(0, &[0u64; 10], 1));
1192 assert_eq!(
1193 poll(Box::pin(cursor.next_change(ChannelMask::one(0))).as_mut()),
1194 Poll::Ready(Change::Progress(Tick(10)))
1195 );
1196 assert_eq!(
1197 poll(Box::pin(cursor.next_change(ChannelMask::one(0))).as_mut()),
1198 Poll::Pending
1199 );
1200 assert_eq!(poll(Box::pin(cursor.sample()).as_mut()), Poll::Pending);
1201 push(&queue, block(10, &[1u64; 10], 1));
1203 assert!(matches!(
1204 poll(Box::pin(cursor.next_change(ChannelMask::one(0))).as_mut()),
1205 Poll::Ready(Change::At { tick: Tick(10), .. })
1206 ));
1207 }
1208
1209 #[test]
1210 fn the_first_sample_after_a_gap_is_no_edge() {
1211 let (mut cursor, queue) = cursor();
1212 push(&queue, block(0, &[0u64; 10], 1));
1213 queue
1214 .borrow_mut()
1215 .try_push(Item::Gap(TickRange::new(Tick(10), Tick(20))))
1216 .map_err(|_| ())
1217 .expect("fits");
1218 push(&queue, block(20, &[1u64; 10], 1));
1219 assert_eq!(
1220 poll(Box::pin(cursor.next_change(ChannelMask::one(0))).as_mut()),
1221 Poll::Ready(Change::Gap(TickRange::new(Tick(10), Tick(20))))
1222 );
1223 assert_eq!(
1224 poll(Box::pin(cursor.sample()).as_mut()),
1225 Poll::Ready(Sample::At {
1226 tick: Tick(20),
1227 levels: Levels(1)
1228 })
1229 );
1230 assert_eq!(
1231 poll(Box::pin(cursor.next_change(ChannelMask::one(0))).as_mut()),
1232 Poll::Ready(Change::Progress(Tick(30)))
1233 );
1234 }
1235
1236 #[test]
1237 fn masks_iterate_channels() {
1238 let mask = ChannelMask::one(3).with(0).with(63);
1239 assert_eq!(mask.iter().collect::<Vec<_>>(), vec![0, 3, 63]);
1240 assert!(ChannelMask::EMPTY.iter().next().is_none());
1241 }
1242}