1const BLOCK: usize = 1024;
56
57#[must_use]
59pub fn count(bytes: &[u8]) -> u64 {
60 let (words, tail_bytes) = bytes.as_chunks::<32>();
61 let (mut a, mut b, mut c, mut d) = (0u32, 0u32, 0u32, 0u32);
62 for w in words {
63 a += u64::from_le_bytes(w[0..8].try_into().expect("eight bytes")).count_ones();
64 b += u64::from_le_bytes(w[8..16].try_into().expect("eight bytes")).count_ones();
65 c += u64::from_le_bytes(w[16..24].try_into().expect("eight bytes")).count_ones();
66 d += u64::from_le_bytes(w[24..32].try_into().expect("eight bytes")).count_ones();
67 }
68 let tail: u32 = tail_bytes.iter().map(|&x| x.count_ones()).sum();
69 u64::from(a) + u64::from(b) + u64::from(c) + u64::from(d) + u64::from(tail)
70}
71
72#[must_use]
78pub fn count_range(bytes: &[u8], from: u64, to: u64) -> u64 {
79 let Some((head, whole, tail)) = split(bytes, from, to) else {
80 return 0;
81 };
82 u64::from(head.count_ones()) + count(whole) + u64::from(tail.count_ones())
83}
84
85#[must_use]
91pub fn find(bytes: &[u8], set: bool, from: u64, to: u64) -> Option<u64> {
92 if from >= to || from >= (bytes.len() as u64) * 8 {
93 return None;
94 }
95 let end = to.min((bytes.len() as u64) * 8);
96 let (first, last) = ((from / 8) as usize, ((end - 1) / 8) as usize);
101 let mut at = first;
102 while at <= last {
103 let mut byte = bytes[at];
104 if !set {
105 byte = !byte;
106 }
107 if at == first {
109 byte &= 0xffu8 >> (from % 8);
110 }
111 if at == last && !end.is_multiple_of(8) {
112 byte &= !(0xffu8 >> (end % 8));
113 }
114 if byte != 0 {
115 return Some(at as u64 * 8 + u64::from(byte.leading_zeros()));
116 }
117 at += 1;
121 let uniform = if set { 0 } else { u64::MAX };
122 while at + 8 <= last {
123 let w = u64::from_ne_bytes(bytes[at..at + 8].try_into().expect("eight bytes"));
124 if w != uniform {
125 break;
126 }
127 at += 8;
128 }
129 }
130 None
131}
132
133fn split(bytes: &[u8], from: u64, to: u64) -> Option<(u8, &[u8], u8)> {
139 let bits = (bytes.len() as u64) * 8;
140 let (from, to) = (from.min(bits), to.min(bits));
141 if from >= to {
142 return None;
143 }
144 let (first, last) = ((from / 8) as usize, ((to - 1) / 8) as usize);
145 let low = 0xffu8 >> (from % 8);
146 let high = if to % 8 == 0 {
147 0xff
148 } else {
149 !(0xffu8 >> (to % 8))
150 };
151 if first == last {
152 return Some((bytes[first] & low & high, &[], 0));
153 }
154 Some((
155 bytes[first] & low,
156 &bytes[first + 1..last],
157 bytes[last] & high,
158 ))
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
168pub enum Op {
169 And,
171 Or,
173 Xor,
175 Not,
177 Diff,
179 Diff1,
181 AndOr,
183 One,
185}
186
187impl Op {
188 #[must_use]
190 pub fn parse(word: &[u8]) -> Option<Op> {
191 const NAMES: [(&[u8], Op); 8] = [
192 (b"and", Op::And),
193 (b"or", Op::Or),
194 (b"xor", Op::Xor),
195 (b"not", Op::Not),
196 (b"diff", Op::Diff),
197 (b"diff1", Op::Diff1),
198 (b"andor", Op::AndOr),
199 (b"one", Op::One),
200 ];
201 NAMES
202 .iter()
203 .find(|(name, _)| name.eq_ignore_ascii_case(word))
204 .map(|&(_, op)| op)
205 }
206
207 #[must_use]
209 pub const fn name(self) -> &'static str {
210 match self {
211 Op::And => "AND",
212 Op::Or => "OR",
213 Op::Xor => "XOR",
214 Op::Not => "NOT",
215 Op::Diff => "DIFF",
216 Op::Diff1 => "DIFF1",
217 Op::AndOr => "ANDOR",
218 Op::One => "ONE",
219 }
220 }
221
222 const fn asymmetric(self) -> bool {
227 matches!(self, Op::Diff | Op::Diff1 | Op::AndOr)
228 }
229}
230
231pub fn width<'a, I>(srcs: I) -> usize
241where
242 I: Iterator<Item = &'a [u8]>,
243{
244 srcs.map(<[u8]>::len).max().expect("BITOP with no source")
245}
246
247pub fn combine<'a, I>(op: Op, srcs: I, out: &mut [u8])
265where
266 I: Iterator<Item = &'a [u8]> + Clone,
267{
268 let mut count = srcs.clone();
269 assert!(count.next().is_some(), "BITOP with no source");
270 assert!(
271 op != Op::Not || count.next().is_none(),
272 "BITOP NOT with more"
273 );
274 let len = out.len();
275
276 let mut blk = [0u8; BLOCK];
281 let mut side = [0u8; BLOCK];
282 let mut at = 0;
283 while at < len {
284 let n = BLOCK.min(len - at);
285 let acc = &mut out[at..at + n];
286 let mut rest = srcs.clone();
287 let first = rest.next().expect("a first source");
288 if op.asymmetric() {
292 load(&mut side[..n], first, at);
293 acc.fill(0);
294 } else {
295 load(acc, first, at);
296 if op == Op::One {
297 side[..n].fill(0);
298 }
299 }
300
301 for src in rest {
302 load(&mut blk[..n], src, at);
303 let s = &blk[..n];
304 match op {
305 Op::And => fold(acc, s, |a, b| a & b),
306 Op::Or | Op::Diff | Op::Diff1 | Op::AndOr => fold(acc, s, |a, b| a | b),
307 Op::Xor => fold(acc, s, |a, b| a ^ b),
308 Op::One => {
309 for (i, &b) in s.iter().enumerate() {
310 side[i] |= acc[i] & b;
311 acc[i] |= b;
312 }
313 }
314 Op::Not => unreachable!("NOT takes one source"),
315 }
316 }
317
318 match op {
319 Op::Not => {
320 for a in acc.iter_mut() {
321 *a = !*a;
322 }
323 }
324 Op::One => fold(acc, &side[..n], |a, b| a & !b),
326 Op::Diff => {
329 for (i, a) in acc.iter_mut().enumerate() {
330 *a = side[i] & !*a;
331 }
332 }
333 Op::Diff1 => {
334 for (i, a) in acc.iter_mut().enumerate() {
335 *a &= !side[i];
336 }
337 }
338 Op::AndOr => {
339 for (i, a) in acc.iter_mut().enumerate() {
340 *a &= side[i];
341 }
342 }
343 Op::And | Op::Or | Op::Xor => {}
344 }
345 at += n;
346 }
347}
348
349fn load(dst: &mut [u8], src: &[u8], at: usize) {
351 let from = at.min(src.len());
352 let take = (src.len() - from).min(dst.len());
353 dst[..take].copy_from_slice(&src[from..from + take]);
354 dst[take..].fill(0);
355}
356
357#[inline]
359fn fold(acc: &mut [u8], src: &[u8], f: impl Fn(u8, u8) -> u8) {
360 for (a, &b) in acc.iter_mut().zip(src) {
361 *a = f(*a, b);
362 }
363}
364
365#[derive(Debug, Clone, Copy, PartialEq, Eq)]
373pub struct Field {
374 signed: bool,
376 bits: u32,
378}
379
380impl Field {
381 #[must_use]
383 pub const fn new(signed: bool, bits: u32) -> Option<Field> {
384 let top = if signed { 64 } else { 63 };
385 if bits == 0 || bits > top {
386 return None;
387 }
388 Some(Field { signed, bits })
389 }
390
391 #[must_use]
393 pub fn parse(word: &[u8]) -> Option<Field> {
394 let (&kind, digits) = word.split_first()?;
395 let signed = match kind {
396 b'i' => true,
397 b'u' => false,
398 _ => return None,
399 };
400 if digits.is_empty() || digits.len() > 2 || !digits.iter().all(u8::is_ascii_digit) {
401 return None;
402 }
403 let bits = digits
404 .iter()
405 .fold(0u32, |n, d| n * 10 + u32::from(d - b'0'));
406 Field::new(signed, bits)
407 }
408
409 #[must_use]
411 pub const fn bits(self) -> u32 {
412 self.bits
413 }
414
415 #[must_use]
417 pub const fn signed(self) -> bool {
418 self.signed
419 }
420
421 #[must_use]
423 pub const fn max(self) -> i64 {
424 if self.signed {
425 if self.bits == 64 {
426 i64::MAX
427 } else {
428 (1i64 << (self.bits - 1)) - 1
429 }
430 } else if self.bits == 63 {
431 i64::MAX
432 } else {
433 (1i64 << self.bits) - 1
434 }
435 }
436
437 #[must_use]
439 pub const fn min(self) -> i64 {
440 if !self.signed {
441 0
442 } else if self.bits == 64 {
443 i64::MIN
444 } else {
445 -(1i64 << (self.bits - 1))
446 }
447 }
448
449 #[must_use]
451 pub const fn last_bit(self, at: u64) -> u64 {
452 at + self.bits as u64 - 1
453 }
454
455 #[must_use]
460 const fn wrapped(self, n: i128) -> i64 {
461 if self.bits == 64 {
462 return n as i64;
463 }
464 let mask = (1i128 << self.bits) - 1;
465 let low = n & mask;
466 if self.signed && low > self.max() as i128 {
467 (low - (1i128 << self.bits)) as i64
468 } else {
469 low as i64
470 }
471 }
472}
473
474#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
476pub enum Overflow {
477 #[default]
479 Wrap,
480 Sat,
482 Fail,
484}
485
486impl Overflow {
487 #[must_use]
489 pub fn parse(word: &[u8]) -> Option<Overflow> {
490 if word.eq_ignore_ascii_case(b"wrap") {
491 Some(Overflow::Wrap)
492 } else if word.eq_ignore_ascii_case(b"sat") {
493 Some(Overflow::Sat)
494 } else if word.eq_ignore_ascii_case(b"fail") {
495 Some(Overflow::Fail)
496 } else {
497 None
498 }
499 }
500}
501
502#[must_use]
504pub fn get(bytes: &[u8], at: u64, f: Field) -> i64 {
505 let raw = window(bytes, at, f.bits);
506 if f.signed && f.bits < 64 && raw >= 1u64 << (f.bits - 1) {
507 (i128::from(raw) - (1i128 << f.bits)) as i64
510 } else {
511 raw as i64
512 }
513}
514
515pub fn set(bytes: &mut [u8], at: u64, f: Field, val: i64) {
522 let last = ((at + u64::from(f.bits) - 1) / 8) as usize;
523 assert!(last < bytes.len(), "the field runs off the end");
524 let (byte, off) = ((at / 8) as usize, (at % 8) as u32);
525 let span = ((off + f.bits).div_ceil(8)) as usize;
526 let mut win: u128 = 0;
529 for &b in &bytes[byte..byte + span] {
530 win = (win << 8) | u128::from(b);
531 }
532 let shift = span as u32 * 8 - off - f.bits;
533 let mask = ((1u128 << f.bits) - 1) << shift;
534 win = (win & !mask) | ((u128::from(val as u64) << shift) & mask);
535 for (i, b) in bytes[byte..byte + span].iter_mut().enumerate() {
536 *b = (win >> ((span - 1 - i) * 8)) as u8;
537 }
538}
539
540fn window(bytes: &[u8], at: u64, bits: u32) -> u64 {
542 let (byte, off) = ((at / 8) as usize, (at % 8) as u32);
543 let span = ((off + bits).div_ceil(8)) as usize;
544 let mut win: u128 = 0;
545 for i in 0..span {
546 win = (win << 8) | u128::from(bytes.get(byte + i).copied().unwrap_or(0));
547 }
548 let shift = span as u32 * 8 - off - bits;
549 let mask = (1u128 << bits) - 1;
550 ((win >> shift) & mask) as u64
551}
552
553#[must_use]
561pub fn setting(f: Field, val: i64, on: Overflow) -> Option<i64> {
562 let want = if f.signed {
563 i128::from(val)
564 } else {
565 i128::from(val as u64)
566 };
567 fit(f, want, on)
568}
569
570#[must_use]
572pub fn adding(f: Field, had: i64, by: i64, on: Overflow) -> Option<i64> {
573 fit(f, i128::from(had) + i128::from(by), on)
574}
575
576fn fit(f: Field, want: i128, on: Overflow) -> Option<i64> {
578 if want > i128::from(f.max()) {
579 return match on {
580 Overflow::Wrap => Some(f.wrapped(want)),
581 Overflow::Sat => Some(f.max()),
582 Overflow::Fail => None,
583 };
584 }
585 if want < i128::from(f.min()) {
586 return match on {
587 Overflow::Wrap => Some(f.wrapped(want)),
588 Overflow::Sat => Some(f.min()),
589 Overflow::Fail => None,
590 };
591 }
592 Some(want as i64)
593}
594
595#[cfg(test)]
596mod tests {
597 use super::*;
598
599 fn slow_bit(bytes: &[u8], at: u64) -> bool {
601 let (byte, off) = ((at / 8) as usize, (at % 8) as u32);
602 bytes.get(byte).is_some_and(|b| b & (0x80 >> off) != 0)
603 }
604
605 fn slow_count(bytes: &[u8], from: u64, to: u64) -> u64 {
606 (from..to).filter(|&i| slow_bit(bytes, i)).count() as u64
607 }
608
609 fn slow_find(bytes: &[u8], set: bool, from: u64, to: u64) -> Option<u64> {
610 (from..to.min((bytes.len() as u64) * 8)).find(|&i| slow_bit(bytes, i) == set)
611 }
612
613 fn slow_get(bytes: &[u8], at: u64, f: Field) -> i64 {
614 let mut raw = 0u64;
615 for i in 0..u64::from(f.bits()) {
616 raw = (raw << 1) | u64::from(slow_bit(bytes, at + i));
617 }
618 if f.signed() && f.bits() < 64 && raw >= 1u64 << (f.bits() - 1) {
619 (i128::from(raw) - (1i128 << f.bits())) as i64
620 } else {
621 raw as i64
622 }
623 }
624
625 fn noise(n: usize, seed: u64) -> Vec<u8> {
627 let mut x = seed | 1;
628 (0..n)
629 .map(|_| {
630 x ^= x << 13;
631 x ^= x >> 7;
632 x ^= x << 17;
633 (x >> 24) as u8
634 })
635 .collect()
636 }
637
638 #[test]
639 fn counting_agrees_with_counting_one_bit_at_a_time() {
640 for len in [0usize, 1, 7, 8, 31, 32, 33, 100, 257] {
641 let bytes = noise(len, len as u64 + 7);
642 assert_eq!(count(&bytes), slow_count(&bytes, 0, len as u64 * 8));
643 }
644 }
645
646 #[test]
647 fn every_range_counts_what_a_bit_loop_counts() {
648 let bytes = noise(37, 99);
649 let bits = 37 * 8;
650 for from in (0..bits).step_by(7) {
651 for to in (from..bits + 16).step_by(5) {
652 assert_eq!(
653 count_range(&bytes, from, to),
654 slow_count(&bytes, from, to.min(bits)),
655 "{from}..{to}"
656 );
657 }
658 }
659 assert_eq!(count_range(&bytes, 10, 10), 0);
661 assert_eq!(count_range(&bytes, 20, 3), 0);
662 assert_eq!(count_range(&[], 0, 64), 0);
663 }
664
665 #[test]
666 fn finding_agrees_with_scanning_one_bit_at_a_time() {
667 let mut bytes = noise(300, 5);
670 bytes[64..128].fill(0);
671 bytes[160..224].fill(0xff);
672 let bits = bytes.len() as u64 * 8;
673 for set in [true, false] {
674 for from in (0..bits).step_by(11) {
675 for to in [from, from + 1, from + 63, from + 700, bits, bits + 9] {
676 assert_eq!(
677 find(&bytes, set, from, to),
678 slow_find(&bytes, set, from, to),
679 "set={set} {from}..{to}"
680 );
681 }
682 }
683 }
684 assert_eq!(find(&[], true, 0, 64), None);
685 assert_eq!(find(&[0xff], false, 0, 8), None);
686 assert_eq!(find(&[0xff], true, 0, 8), Some(0));
687 }
688
689 #[test]
690 fn a_bit_is_counted_from_the_top_of_the_first_byte() {
691 assert_eq!(find(&[0x01], true, 0, 8), Some(7));
692 assert_eq!(find(&[0x80], true, 0, 8), Some(0));
693 assert_eq!(count(&[0x01]), 1);
694 }
695
696 #[test]
698 fn the_eight_operations_are_what_a_real_server_does() {
699 let a: &[u8] = &[0xf0, 0x0f, 0xff];
700 let b: &[u8] = &[0xff, 0x00];
701 let c: &[u8] = &[0x0f];
702 let mut out = Vec::new();
703 let run = |op, srcs: &[&[u8]], out: &mut Vec<u8>| {
704 out.clear();
705 out.resize(width(srcs.iter().copied()), 0);
706 combine(op, srcs.iter().copied(), out);
707 };
708
709 run(Op::And, &[a, b], &mut out);
710 assert_eq!(out, vec![0xf0, 0x00, 0x00], "and, padded with zeros");
711 run(Op::Or, &[a, b], &mut out);
712 assert_eq!(out, vec![0xff, 0x0f, 0xff]);
713 run(Op::Xor, &[a, b], &mut out);
714 assert_eq!(out, vec![0x0f, 0x0f, 0xff]);
715 run(Op::Not, &[a], &mut out);
716 assert_eq!(out, vec![0x0f, 0xf0, 0x00]);
717 run(Op::Diff, &[a, b], &mut out);
718 assert_eq!(out, vec![0x00, 0x0f, 0xff], "in a and in nothing else");
719 run(Op::Diff1, &[a, b], &mut out);
720 assert_eq!(out, vec![0x0f, 0x00, 0x00], "in the others and not in a");
721 run(Op::AndOr, &[a, b, c], &mut out);
722 assert_eq!(out, vec![0xf0, 0x00, 0x00]);
723 run(Op::One, &[a, b, c], &mut out);
724 assert_eq!(out, vec![0x00, 0x0f, 0xff], "set in exactly one of them");
725
726 for op in [Op::And, Op::Or, Op::Xor, Op::One] {
728 run(op, &[a], &mut out);
729 assert_eq!(out, a, "{} of one source", op.name());
730 }
731 }
732
733 #[test]
735 fn combining_crosses_the_block_boundary() {
736 let a = noise(BLOCK * 2 + 37, 1);
737 let b = noise(BLOCK + 3, 2);
738 let c = noise(BLOCK * 3, 3);
739 let srcs: [&[u8]; 3] = [&a, &b, &c];
740 let mut out = Vec::new();
741
742 let at = |s: &[u8], i: usize| s.get(i).copied().unwrap_or(0);
743 for op in [
744 Op::And,
745 Op::Or,
746 Op::Xor,
747 Op::Diff,
748 Op::Diff1,
749 Op::AndOr,
750 Op::One,
751 ] {
752 out.clear();
753 out.resize(width(srcs.iter().copied()), 0);
754 combine(op, srcs.iter().copied(), &mut out);
755 assert_eq!(out.len(), c.len(), "{}", op.name());
756 for (i, &got) in out.iter().enumerate() {
757 let (x, y, z) = (at(&a, i), at(&b, i), at(&c, i));
758 let want = match op {
759 Op::And => x & y & z,
760 Op::Or => x | y | z,
761 Op::Xor => x ^ y ^ z,
762 Op::Diff => x & !(y | z),
763 Op::Diff1 => (y | z) & !x,
764 Op::AndOr => x & (y | z),
765 Op::One => (x & !y & !z) | (y & !x & !z) | (z & !x & !y),
766 Op::Not => unreachable!(),
767 };
768 assert_eq!(got, want, "{} at byte {i}", op.name());
769 }
770 }
771 }
772
773 #[test]
774 fn an_operation_is_named_in_any_case() {
775 assert_eq!(Op::parse(b"AND"), Some(Op::And));
776 assert_eq!(Op::parse(b"diff1"), Some(Op::Diff1));
777 assert_eq!(Op::parse(b"AnDoR"), Some(Op::AndOr));
778 assert_eq!(Op::parse(b"nope"), None);
779 assert_eq!(Op::And.name(), "AND");
780 }
781
782 #[test]
783 fn a_field_type_is_a_letter_and_a_width() {
784 assert_eq!(Field::parse(b"u8").map(Field::bits), Some(8));
785 assert_eq!(Field::parse(b"i64").map(Field::signed), Some(true));
786 assert_eq!(Field::parse(b"u63").map(Field::bits), Some(63));
787 assert_eq!(Field::parse(b"u64"), None);
790 assert_eq!(Field::parse(b"i65"), None);
791 assert_eq!(Field::parse(b"u0"), None);
792 assert_eq!(Field::parse(b"x8"), None);
793 assert_eq!(Field::parse(b"u"), None);
794 assert_eq!(Field::parse(b""), None);
795 assert_eq!(Field::parse(b"u008"), None);
796 }
797
798 #[test]
799 fn a_field_knows_its_own_range() {
800 let f = |s, b| Field::new(s, b).expect("a width");
801 assert_eq!((f(false, 8).min(), f(false, 8).max()), (0, 255));
802 assert_eq!((f(true, 8).min(), f(true, 8).max()), (-128, 127));
803 assert_eq!((f(true, 1).min(), f(true, 1).max()), (-1, 0));
804 assert_eq!((f(false, 1).min(), f(false, 1).max()), (0, 1));
805 assert_eq!((f(true, 64).min(), f(true, 64).max()), (i64::MIN, i64::MAX));
806 assert_eq!((f(false, 63).min(), f(false, 63).max()), (0, i64::MAX));
807 }
808
809 #[test]
810 fn reading_and_writing_a_field_agrees_with_a_bit_loop() {
811 let mut bytes = noise(64, 3);
812 for bits in [1u32, 2, 7, 8, 9, 31, 32, 33, 63, 64] {
813 for signed in [true, false] {
814 let Some(f) = Field::new(signed, bits) else {
815 continue;
816 };
817 for at in 0..64u64 {
818 assert_eq!(get(&bytes, at, f), slow_get(&bytes, at, f), "{f:?} at {at}");
819 }
820 }
821 }
822 let f = Field::new(false, 16).expect("a width");
825 assert_eq!(get(&[0xff], 0, f), 0xff00);
826 assert_eq!(get(&[], 0, f), 0);
827
828 for bits in [1u32, 5, 8, 13, 32, 64] {
830 for signed in [true, false] {
831 let Some(f) = Field::new(signed, bits) else {
832 continue;
833 };
834 for at in [0u64, 1, 7, 8, 63, 100] {
835 for want in [f.min(), f.max()] {
838 set(&mut bytes, at, f, want);
839 assert_eq!(get(&bytes, at, f), want, "{f:?} at {at}");
840 }
841 }
842 }
843 }
844 }
845
846 #[test]
847 fn a_write_leaves_the_bits_around_it_alone() {
848 let mut bytes = [0xffu8; 4];
849 let f = Field::new(false, 3).expect("a width");
850 set(&mut bytes, 5, f, 0);
851 assert_eq!(bytes, [0xf8, 0xff, 0xff, 0xff]);
852 set(&mut bytes, 29, f, 0);
853 assert_eq!(bytes, [0xf8, 0xff, 0xff, 0xf8]);
854 }
855
856 #[test]
858 fn overflow_is_what_a_real_server_does() {
859 let u8f = Field::new(false, 8).expect("a width");
860 let i8f = Field::new(true, 8).expect("a width");
861
862 assert_eq!(setting(u8f, 300, Overflow::Wrap), Some(44));
863 assert_eq!(setting(u8f, 300, Overflow::Sat), Some(255));
864 assert_eq!(setting(u8f, 300, Overflow::Fail), None);
865 assert_eq!(setting(u8f, -5, Overflow::Wrap), Some(251));
867 assert_eq!(setting(u8f, -5, Overflow::Sat), Some(255));
868 assert_eq!(setting(u8f, -5, Overflow::Fail), None);
869 assert_eq!(setting(i8f, -200, Overflow::Sat), Some(-128));
871 assert_eq!(setting(i8f, 200, Overflow::Sat), Some(127));
872 assert_eq!(setting(i8f, -200, Overflow::Wrap), Some(56));
873
874 assert_eq!(adding(u8f, 255, 10, Overflow::Wrap), Some(9));
875 assert_eq!(adding(u8f, 255, 250, Overflow::Sat), Some(255));
876 assert_eq!(adding(u8f, 255, 250, Overflow::Fail), None);
877 assert_eq!(adding(u8f, 0, -1000, Overflow::Sat), Some(0));
878 assert_eq!(adding(u8f, 0, -1, Overflow::Wrap), Some(255));
879
880 let i64f = Field::new(true, 64).expect("a width");
881 assert_eq!(adding(i64f, i64::MAX, 1, Overflow::Wrap), Some(i64::MIN));
882 assert_eq!(adding(i64f, i64::MAX, 1, Overflow::Sat), Some(i64::MAX));
883 assert_eq!(adding(i64f, i64::MIN, -1, Overflow::Sat), Some(i64::MIN));
884 assert_eq!(adding(i64f, i64::MIN, -1, Overflow::Fail), None);
885
886 let u1 = Field::new(false, 1).expect("a width");
887 assert_eq!(adding(u1, 1, 5, Overflow::Sat), Some(1));
888 assert_eq!(adding(u1, 1, 3, Overflow::Wrap), Some(0));
889 }
890
891 #[test]
892 fn an_overflow_word_is_read_in_any_case() {
893 assert_eq!(Overflow::parse(b"WRAP"), Some(Overflow::Wrap));
894 assert_eq!(Overflow::parse(b"sat"), Some(Overflow::Sat));
895 assert_eq!(Overflow::parse(b"Fail"), Some(Overflow::Fail));
896 assert_eq!(Overflow::parse(b"nope"), None);
897 assert_eq!(Overflow::default(), Overflow::Wrap);
898 }
899}