1use crate::prelude::*;
71
72pub type RangeCount = u32;
75
76type Tail1 = u8;
77
78const BITS_PER_DIGIT: usize = 5;
79const DIGITS_PER_LIMB: usize = 10;
80
81type RawLimbVal = u64;
82#[derive(Copy,Clone,Eq,PartialEq,Ord,PartialOrd)]
83#[derive(Neg,Add,BitAnd,Sub,Shr,ShrAssign)]
84pub struct LimbVal(Wrapping<RawLimbVal>);
85
86const DELTA: LimbVal = lv(0x4000_0000);
87const ZERO: LimbVal = lv(0);
88const ONE: LimbVal = lv(1);
89const MINUS_ONE: LimbVal = lv(-1i64 as u64);
90
91const RAW_LIMB_MODULUS: RawLimbVal = 1u64 << BITS_PER_LIMB;
92
93const BITS_PER_LIMB: usize = BITS_PER_DIGIT * DIGITS_PER_LIMB;
94const DIGIT_MASK: LimbVal = lv((1u64 << BITS_PER_DIGIT) - 1);
95const TEXT_PER_LIMB: usize = DIGITS_PER_LIMB + 1;
96const LIMB_MODULUS: LimbVal = lv(RAW_LIMB_MODULUS);
97const LIMB_MASK: LimbVal = lv(RAW_LIMB_MODULUS - 1);
98
99#[derive(DeserializeFromStr,SerializeDisplay)]
100pub struct ZCoord(innards::Innards);
101
102#[derive(Error,Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize)]
103#[error("error parsing Z coordinate")]
104pub struct ParseError;
105
106#[derive(Error,Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize)]
107pub enum RangeImpossible {
108 #[error("Z coordinate range has end before start, cannot iterate")]
109 Backwards,
110 #[error("Z coordinate range has end equal to start, cannot iterate")]
111 Empty,
112}
113
114#[derive(Error,Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize)]
115#[error("Z coordinate range has neither end, cannot iterate")]
116pub struct TotallyUnboundedRange;
117
118#[derive(Error,Debug,Copy,Clone,Eq,PartialEq,Serialize,Deserialize)]
119#[error("Z coordinate overflow")]
120pub struct Overflow;
121
122#[derive(Error,Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize)]
123pub enum LogicError {
124 #[error("{0}")] RangeTotallyUnbounded(#[from] TotallyUnboundedRange),
125 #[error("{0}")] RangeImpossible (#[from] RangeImpossible ),
126}
127
128impl From<RawLimbVal> for LimbVal {
131 fn from(raw: RawLimbVal) -> LimbVal { lv(raw) }
132}
133
134const fn lv(raw: RawLimbVal) -> LimbVal { LimbVal(Wrapping(raw)) }
135
136impl LimbVal {
137 pub fn primitive(self) -> RawLimbVal { self.0.0 }
138 pub fn to_str_buf(self, out: &mut [Tail1; DIGITS_PER_LIMB]) -> LimbVal {
140 let mut l = self;
141 for p in out.iter_mut().rev() {
142 let v = (l & DIGIT_MASK).primitive() as u8;
143 *p = if v < 10 { b'0' + v } else { (b'a' - 10) + v };
144 l >>= BITS_PER_DIGIT;
145 }
146 l
147 }
148}
149
150impl Display for LimbVal {
151 #[throws(fmt::Error)]
152 fn fmt(&self, f: &mut fmt::Formatter) {
153 let mut buf = [0u8; DIGITS_PER_LIMB];
154 let lhs: RawLimbVal = self.to_str_buf(&mut buf).primitive();
155 if lhs != 0 {
156 write!(f, "{:#x?}_!_", lhs)?;
157 }
158 write!(f, "{}", str::from_utf8(&buf).unwrap())?;
159 }
160}
161
162impl Debug for LimbVal {
163 #[throws(fmt::Error)]
164 fn fmt(&self, f: &mut fmt::Formatter) {
165 write!(f, "lv(")?;
166 Display::fmt(self, f)?;
167 write!(f, ")")?;
168 }
169}
170
171#[derive(Clone,Debug)]
174pub struct Mutable {
175 limbs: Vec<LimbVal>,
176}
177
178impl ZCoord {
179 pub fn clone_mut(&self) -> Mutable {
180 Mutable::from_u8_unchecked(self.tail())
181 }
182}
183
184impl Mutable {
185 fn from_u8_unchecked(tail: &[u8]) -> Mutable {
186 let nlimbs = (tail.len() + 1) / TEXT_PER_LIMB;
187 let mut limbs = Vec::with_capacity(nlimbs + 2);
188 for lt in tail.chunks(TEXT_PER_LIMB) {
189 let s = str::from_utf8(<[0..DIGITS_PER_LIMB]).unwrap();
190 let v = RawLimbVal::from_str_radix(s, 1 << BITS_PER_DIGIT).unwrap();
191 limbs.push(v.into());
192 }
193 Mutable { limbs }
194 }
195}
196
197impl From<TryFromIntError> for Overflow {
198 fn from(_: TryFromIntError) -> Overflow { Overflow }
199}
200
201pub trait AddSubOffset {
202 fn init_delta(&self) -> LimbVal;
203 const CARRY_DELTA : LimbVal;
204 const NEW_LIMBS : LimbVal;
205 fn check_underflow(m: &Mutable, i: usize, nv: LimbVal) -> Option<()>;
206 #[throws(as Option)]
207 fn check_nospace(i: usize) { if i == 0 { throw!() } }
208 fn start_limb(&self, m: &Mutable) -> usize { m.limbs.len() - 1 }
209 fn final_undo_delta() -> LimbVal;
210 const SEALED_TRAIT: Sealed;
211}
212
213pub struct Sealed(());
214
215#[derive(Debug)]
216pub struct Increment;
217impl AddSubOffset for Increment {
218 fn init_delta(&self) -> LimbVal { DELTA }
219 const CARRY_DELTA : LimbVal = ONE;
220 const NEW_LIMBS : LimbVal = ZERO;
221 #[throws(as Option)]
222 fn check_underflow(_: &Mutable, _: usize, _: LimbVal) { }
223 fn final_undo_delta() -> LimbVal { DELTA }
224 const SEALED_TRAIT: Sealed = Sealed(());
225}
226
227#[derive(Debug)]
228pub struct Decrement;
229impl AddSubOffset for Decrement {
230 fn init_delta(&self) -> LimbVal { -DELTA }
231 const CARRY_DELTA : LimbVal = MINUS_ONE;
232 const NEW_LIMBS : LimbVal = LIMB_MASK;
233 #[throws(as Option)]
234 fn check_underflow(_: &Mutable, i: usize, nv: LimbVal) {
235 if i == 0 && nv == ZERO { throw!() }
236 }
237 fn final_undo_delta() -> LimbVal { -DELTA + ONE }
238 const SEALED_TRAIT: Sealed = Sealed(());
239}
240
241impl Mutable {
242 #[throws(Overflow)]
243 fn addsub<ASO:AddSubOffset>(&mut self, aso: &ASO) -> ZCoord {
244 'attempt: loop {
245 let mut i = aso.start_limb(self);
246 let mut delta = aso.init_delta();
247
248 if (||{
249 loop {
250 let nv = self.limbs[i] + delta;
251 self.limbs[i] = nv & LIMB_MASK;
252 ASO::check_underflow(self, i, nv)?;
253 if nv < LIMB_MODULUS { return Some(()) }
254 ASO::check_nospace(i)?;
255 i -= 1;
256 delta = ASO::CARRY_DELTA;
257 }
258 })() == Some(()) { break 'attempt }
259
260 loop {
262 if i >= self.limbs.len() { break }
263 else if i == aso.start_limb(self) { delta = ASO::final_undo_delta(); }
264 let nv = self.limbs[i] - delta;
265 self.limbs[i] = nv & LIMB_MASK;
266 i += 1;
267 }
268 self.limbs.push(ASO::NEW_LIMBS);
269 self.limbs.push(ASO::NEW_LIMBS);
270 }
271 self.repack()?
272 }
273
274 #[throws(Overflow)]
275 pub fn increment(&mut self) -> ZCoord { self.addsub(&Increment)? }
276 #[throws(Overflow)]
277 pub fn decrement(&mut self) -> ZCoord { self.addsub(&Decrement)? }
278
279 #[throws(Overflow)]
280 pub fn repack(&self) -> ZCoord {
281 let mut limbs = self.limbs.as_slice();
282 while let Some(l) = limbs.strip_suffix(&[ZERO]) { limbs = l }
283
284 let taillen = (limbs.len() * TEXT_PER_LIMB - 1).try_into()?;
285 let mut bf = ZCoord::alloc(taillen);
286 let mut w = bf.tail_mut();
287
288 for l in limbs.iter().cloned() {
289 if l >= LIMB_MODULUS { throw!(Overflow) };
290 l.to_str_buf((&mut w[0..DIGITS_PER_LIMB]).try_into().unwrap());
291 if let Some(p) = w.get_mut(DIGITS_PER_LIMB) {
292 *p = b'_';
293 } else {
294 break;
295 }
296 w = &mut w[TEXT_PER_LIMB..];
297 }
298 bf
299 }
300}
301
302pub type RangeIterator = std::iter::Take<
303 IteratorCore<AddSubRangeDelta, MutateFirst>
304 >;
305
306pub trait MutateReturn: Copy {
307 fn op<T, U,
308 M: FnOnce(&mut T),
309 O: FnOnce(&T) -> U>
310 (self,
311 x: &mut T,
312 m: M,
313 o: O) -> U;
314}
315
316#[derive(Debug,Copy,Clone)]
317pub struct MutateFirst;
318impl MutateReturn for MutateFirst {
319 fn op<T, U,
320 M: FnOnce(&mut T),
321 O: FnOnce(&T) -> U>
322 (self, x: &mut T, m: M, o: O) -> U
323 {
324 m(x);
325 o(x)
326 }
327}
328
329#[derive(Debug,Copy,Clone)]
330pub struct MutateLast;
331impl MutateReturn for MutateLast {
332 fn op<T, U,
333 M: FnOnce(&mut T),
334 O: FnOnce(&T) -> U>
335 (self, x: &mut T, m: M, o: O) -> U
336 {
337 let u = o(x);
338 m(x);
339 u
340 }
341}
342
343#[derive(Debug)]
344pub struct IteratorCore<ASO, MR> {
345 current: Mutable,
346 aso: ASO,
347 mr: MR,
348}
349
350#[derive(Debug)]
351pub struct AddSubRangeDelta {
352 i: usize,
353 step: LimbVal,
354}
355impl AddSubOffset for AddSubRangeDelta {
356 fn init_delta(&self) -> LimbVal { self.step }
357 const CARRY_DELTA : LimbVal = ONE;
358 const NEW_LIMBS : LimbVal = ZERO;
359 #[throws(as Option)]
360 fn check_underflow(_: &Mutable, _: usize, _: LimbVal) { }
361 #[throws(as Option)]
362 fn check_nospace(i: usize) { assert_ne!(i, 0) }
363 fn start_limb(&self, _: &Mutable) -> usize { self.i }
364 fn final_undo_delta() -> LimbVal { panic!() }
365 const SEALED_TRAIT: Sealed = Sealed(());
366}
367
368impl Mutable {
369 fn limb_val_lookup(&self, i: usize) -> LimbVal {
370 *self.limbs.get(i).unwrap_or(&ZERO)
371 }
372 fn extend_to_limb(&mut self, i: usize) {
373 if self.limbs.len() <= i {
374 self.limbs.resize(i+1, ZERO);
375 }
376 }
377
378 #[throws(RangeImpossible)]
379 fn range_core(a: &Mutable, b: &Mutable, count: RangeCount)
380 -> (Mutable, AddSubRangeDelta) {
381 type ASRD = AddSubRangeDelta;
382 let count = count as RawLimbVal;
383 let mut current = a.clone();
384 let mut borrowing = false;
385 let aso = 'ok: loop { for i in 0.. {
386 if i > a.limbs.len() && i > b.limbs.len() {
387 throw!(RangeImpossible::Empty);
391 }
392 current.extend_to_limb(i);
395
396 let la = a.limb_val_lookup(i);
397 let lb = b.limb_val_lookup(i);
398 if la == lb && ! borrowing {
399 continue
402 }
403
404 let wantgaps = count+1;
405 let avail = (lb.primitive() as i64) - (la.primitive() as i64)
406 + if borrowing { RAW_LIMB_MODULUS as i64 } else { 0};
407 if avail < 0 { throw!(RangeImpossible::Backwards) }
408 let avail = avail as u64;
409
410 if avail < 2 {
411 borrowing = true;
414 continue;
415 }
416 let mut i = i;
419 let (step, init);
420 if avail >= wantgaps {
421 step = avail / wantgaps;
424 init = la;
427 } else {
428 current.limbs[i] = la + (avail/2).into();
431 i += 1;
432 step = (RAW_LIMB_MODULUS-1) / wantgaps;
433 init = ZERO;
434 }
435 current.extend_to_limb(i);
436 current.limbs[i] = init;
437 break 'ok ASRD { i, step: step.into() };
438 } };
439 (current, aso)
440 }
441
442 #[throws(RangeImpossible)]
443 pub fn range_upto(&self, other: &Mutable, count: RangeCount)
447 -> RangeIterator {
448 let (current, aso) = Mutable::range_core(self, other, count)?;
449 IteratorCore { current, aso, mr: MutateFirst }.take(count as usize)
450 }
451}
452
453impl<ASO:AddSubOffset, MR:MutateReturn> Iterator for IteratorCore<ASO, MR> {
454 type Item = ZCoord;
455 fn next(&mut self) -> Option<ZCoord> {
456 let aso = &self.aso;
457 Some(self.mr.op(
458 &mut self.current,
459 |current| { current.addsub(aso).unwrap(); },
460 |current| { current.repack().unwrap() },
461 ))
462 }
463}
464
465pub trait BoxedIteratorTrait: Iterator<Item = ZCoord> + Debug { }
466pub type BoxedIterator = Box<dyn BoxedIteratorTrait>;
467impl<T> BoxedIteratorTrait for T where T: Iterator<Item = ZCoord> + Debug {}
468
469impl Mutable {
470 pub fn iter<ASO:AddSubOffset>(self, aso: ASO)
472 -> IteratorCore<ASO, impl MutateReturn + Debug>
473 {
474 IteratorCore { current: self, aso, mr: MutateFirst }
475 }
476 #[throws(LogicError)]
477 pub fn some_range(a: Option<&Mutable>, b: Option<&Mutable>,
479 count: RangeCount) -> BoxedIterator {
480 fn mk<T:'static + Debug + Iterator<Item=ZCoord>>(x: T) -> BoxedIterator
481 { Box::new(x) }
482 let c = count as usize;
483 if c == 0 { return mk( iter::empty() ) }
484 match (a, b) {
485 (None, None ) => throw!(TotallyUnboundedRange),
486 (Some(a), None ) => mk( a.clone().iter(Increment).take(c) ),
487 (Some(a), Some(b)) => mk( Mutable::range_upto(a,b,count)? ),
488 (None, Some(b)) => mk({
489 let mut first = b.clone();
490 first.addsub(&Decrement).unwrap();
491 let (current, aso) = Mutable::range_core(&first, b, count-1)?;
492 IteratorCore { current, aso, mr: MutateLast }.take(c)
493 }),
494 }
495 }
496}
497
498impl FromStr for Mutable {
499 type Err = ParseError;
500 #[throws(ParseError)]
501 fn from_str(s: &str) -> Mutable {
502 let tail = ZCoord::checked(s)?;
503 Mutable::from_u8_unchecked(tail)
504 }
505}
506
507impl ZCoord {
510 pub fn as_str(&self) -> &str {
511 let tail = self.tail();
512 str::from_utf8(tail).unwrap()
513 }
514}
515
516impl Display for ZCoord {
517 #[throws(fmt::Error)]
518 fn fmt(&self, f: &mut Formatter) {
519 write!(f, "{}", self.as_str())?
520 }
521}
522
523impl Debug for ZCoord {
524 #[throws(fmt::Error)]
525 fn fmt(&self, f: &mut Formatter) {
526 write!(f, r#"Zc""#)?;
527 <ZCoord as Display>::fmt(self, f)?;
528 write!(f, r#"""#)?;
529 }
530}
531
532impl Ord for ZCoord {
533 fn cmp(&self, other: &ZCoord) -> Ordering {
534 let at = self.tail();
535 let bt = other.tail();
536 at.cmp(bt)
537 }
538}
539impl PartialOrd for ZCoord {
540 fn partial_cmp(&self, other: &ZCoord) -> Option<Ordering> {
541 Some(self.cmp(other))
542 }
543}
544impl Eq for ZCoord { }
545impl PartialEq for ZCoord {
546 fn eq(&self, other: &ZCoord) -> bool {
547 self.cmp(other) == Ordering::Equal
548 }
549}
550
551impl TryFrom<&str> for ZCoord {
552 type Error = ParseError;
553 #[throws(ParseError)]
554 fn try_from(s: &str) -> ZCoord { ZCoord::from_str(s)? }
555}
556
557impl FromStr for ZCoord {
558 type Err = ParseError;
559 #[throws(ParseError)]
560 fn from_str(s: &str) -> ZCoord {
561 let tail = ZCoord::checked(s)?;
562 ZCoord::alloc_copy(tail).unwrap()
563 }
564}
565
566const DEFAULT_TEXT: &[u8] = b"g000000000";
571
572impl Default for ZCoord {
573 fn default() -> ZCoord {
574 ZCoord::alloc_copy(DEFAULT_TEXT).unwrap()
575 }
576}
577
578impl ZCoord {
579 #[throws(ParseError)]
580 fn checked(s: &str) -> &[u8] {
581 let s = s.as_bytes();
582 let nomlen = s.len() + 1;
583 if nomlen % TEXT_PER_LIMB !=0 { throw!(ParseError) }
584 let _: innards::Taillen = (nomlen / TEXT_PER_LIMB).try_into()
585 .map_err(|_:TryFromIntError| ParseError)?;
586 for lt in s.chunks(TEXT_PER_LIMB) {
587 if !lt[0..DIGITS_PER_LIMB].iter().all(
588 |c: &u8| {
589 (b'0'..=b'9').contains(c) ||
590 (b'a'..=b'v').contains(c)
591 }) { throw!(ParseError) }
592 match lt[DIGITS_PER_LIMB..] {
593 [] | [b'_'] => (),
594 _ => throw!(ParseError)
595 };
596 }
597 if &s[s.len() - DIGITS_PER_LIMB..] == b"0000000000" {
598 throw!(ParseError)
599 }
600 s
601 }
602
603 #[throws(ParseError)]
604 pub fn check_str(s: &str) {
605 Self::checked(s)?;
606 }
607}
608
609impl TryFrom<&Mutable> for ZCoord {
610 type Error = Overflow;
611 #[throws(Overflow)]
612 fn try_from(m: &Mutable) -> ZCoord { m.repack()? }
613}
614
615mod innards {
618 use std::alloc::{self, Layout};
619 use std::mem::{self, align_of, size_of};
620 use std::ptr::{self, NonNull};
621 use std::slice;
622 use super::*;
623
624 unsafe impl Send for ZCoord { }
625 unsafe impl Sync for ZCoord { }
626
627 pub(super)
628 type Innards = NonNull<u8>;
629 pub type Taillen = u16;
630
631 pub(super)
632 struct Header {
633 pub taillen: u16, }
635
636 #[repr(C)]
637 #[allow(dead_code)] struct Repr {
639 h: Header,
640 d: [Tail1],
641 }
642
643 const OFFSET: usize = {
644 let h_size = size_of::<Header>();
645 let l_align = align_of::<Tail1>();
646 l_align * ((h_size + l_align - 1) / l_align)
647 };
648
649 fn layout(len: Taillen) -> (usize, Layout) {
650 let tail_nbytes: usize = size_of::<Tail1>() * (len as usize);
651 let all_nbytes = OFFSET + tail_nbytes;
652 let align = max(align_of::<Header>(), align_of::<Tail1>());
653 (all_nbytes, Layout::from_size_align(all_nbytes, align).unwrap())
654 }
655
656 fn ptrs(p: *mut u8) -> (*mut Header, *mut Tail1) { unsafe {
657 let p_header : *mut Header = mem::transmute(p);
658 let p_tail : *mut Tail1 = mem::transmute(p.add(OFFSET));
659 (p_header, p_tail)
660 } }
661
662 impl ZCoord {
663 unsafe fn alloc_unsafe<F>(taillen: Taillen, f:F) -> ZCoord
664 where F: FnOnce(*mut Tail1)
665 {
666 #[allow(unused_unsafe)] unsafe {
668 let p = alloc::alloc(layout(taillen).1);
669 let (p_header, p_tail) = ptrs(p);
670 ptr::write(p_header, Header { taillen });
671 f(p_tail);
672 ZCoord(NonNull::new(p).unwrap())
673 }
674 }
675
676 pub(super)
677 fn alloc(taillen: Taillen) -> ZCoord {
678 unsafe {
679 ZCoord::alloc_unsafe(taillen, |nt: *mut Tail1| {
680 ptr::write_bytes(nt, 0, taillen as usize);
681 })
682 }
683 }
684
685 #[throws(Overflow)]
686 pub(super)
687 fn alloc_copy(tail: &[Tail1]) -> ZCoord {
688 let taillen = tail.len().try_into()?;
689 unsafe {
690 ZCoord::alloc_unsafe(taillen, |nt: *mut Tail1| {
691 ptr::copy_nonoverlapping(tail.as_ptr(), nt, taillen as usize);
692 })
693 }
694 }
695
696 pub(super) fn tail(&self) -> &[Tail1] {
697 unsafe {
698 let (h, t) = ptrs(self.0.as_ptr());
699 let h = h.as_ref().unwrap();
700 slice::from_raw_parts(t, h.taillen as usize)
701 }
702 }
703
704 pub(super)
705 fn tail_mut(&mut self) -> &mut [Tail1] {
706 unsafe {
707 let (h, t) = ptrs(self.0.as_ptr());
708 let h = h.as_ref().unwrap();
709 slice::from_raw_parts_mut(t, h.taillen as usize)
710 }
711 }
712
713 fn layout(&self) -> (usize, Layout) {
714 unsafe {
715 let (h, _) = ptrs(self.0.as_ptr());
716 let h = h.as_ref().unwrap();
717 let taillen = h.taillen;
718 layout(taillen)
719 }
720 }
721
722 #[throws(Overflow)]
723 pub fn plus_offset(&self, offset: u32) -> Self { unsafe {
724 let (old_header, old_tail) = ptrs(self.0.as_ptr());
725 let old_taillen = old_header.as_ref().unwrap().taillen;
726 let new_taillen = old_taillen
727 .checked_add(TEXT_PER_LIMB as Taillen).ok_or(Overflow)?;
728 let old_taillen: usize = old_taillen.into();
729 let new_limb = lv(
730 (offset as RawLimbVal) << (BITS_PER_LIMB - 32) |
731 1 << (BITS_PER_LIMB - 33)
732 );
733 let mut buf: [u8; TEXT_PER_LIMB] = default();
734 buf[0] = b'_';
735 new_limb.to_str_buf((&mut buf[1..TEXT_PER_LIMB]).try_into().unwrap());
736 ZCoord::alloc_unsafe(new_taillen, |new_tail| {
737 ptr::copy_nonoverlapping(old_tail,
738 new_tail,
739 old_taillen);
740
741 ptr::copy_nonoverlapping(buf.as_ptr(),
742 new_tail.add(old_taillen),
743 TEXT_PER_LIMB);
744 })
745 } }
746 }
747
748 impl Drop for ZCoord {
749 fn drop(&mut self) {
750 let layout = self.layout().1;
751 unsafe {
752 alloc::dealloc(self.0.as_mut(), layout);
753 }
754 }
755 }
756
757 impl Clone for ZCoord {
758 fn clone(&self) -> ZCoord {
759 let (all_bytes, layout) = self.layout();
760 unsafe {
761 let p = alloc::alloc(layout);
762 ptr::copy_nonoverlapping(self.0.as_ptr(), p, all_bytes);
763 ZCoord(NonNull::new(p).unwrap())
764 }
765 }
766 }
767
768 impl Hash for ZCoord {
769 fn hash<H:Hasher>(&self, state: &mut H) {
770 self.tail().hash(state)
771 }
772 }
773
774}
775
776#[cfg(test)]
779mod test {
780 use crate::misc::default;
781 use super::*;
782 use std::collections::hash_map::DefaultHasher;
783 use std::mem;
784
785 fn zc(s: &str) -> ZCoord { ZCoord::from_str(s).unwrap() }
786 fn mk(s: &str) -> super::Mutable { zc(s).clone_mut() }
787
788 #[test]
789 fn bfparse() {
790 let s = "gg0123abcd_0123456789";
791 let b = ZCoord::from_str(s).unwrap();
792 let b2 = b.clone();
793 assert_eq!(format!("{}", &b), s);
794 assert_eq!(format!("{}", &b.clone_mut().repack().unwrap()), s);
795 mem::drop(b);
796 assert_eq!(format!("{}", &b2), s);
797 assert_eq!(format!("{:?}", &b2),
798 format!(r#"Zc"{}""#, &b2));
799 fn bad(s: &str) { assert_eq!(Err(ParseError), ZCoord::from_str(s)); }
800 bad("");
801 bad("0");
802 bad("0000000000");
803 bad("1111111111_0000000000");
804 bad("0000000000_0000000000");
805 bad("aaaaaaaa0_aaaaaaaa00");
806 bad("aaaaaaaa0_aaaaaaaa00");
807 bad("aaaaaaaa00_aaaaaaaa0");
808 bad("#aaaaaaaa0_aaaaaaaa00");
809 bad("aaaaaaaa0#_aaaaaaaa00");
810 bad("aaaaaaaa00#aaaaaaaa00");
811 bad("aaaaaaaa00_aaaaaaaa0#");
812 bad("Zaaaaaaaa0_#aaaaaaaa0");
813 bad("Aaaaaaaaa0_#aaaaaaaa0");
814 bad("waaaaaaaa0_#aaaaaaaa0");
815 bad("/aaaaaaaa0_#aaaaaaaa0");
816 bad(":aaaaaaaa0_#aaaaaaaa0");
817 bad("`aaaaaaaa0_#aaaaaaaa0");
818 }
819
820 #[test]
821 fn limb_debug() {
822 fn chk(raw: RawLimbVal, disp: &str) {
823 let l: LimbVal = raw.into();
824 let dbg = format!("lv({})", &disp);
825 assert_eq!( &format!("{}", &l), disp );
826 assert_eq!( &format!("{:?}", &l), &dbg );
827 }
828 chk(0x42, "0000000022");
829 chk(0x42 + RAW_LIMB_MODULUS * 0x33, "0x33_!_0000000022");
830 chk(0x42 + RAW_LIMB_MODULUS * 0x3fae, "0x3fae_!_0000000022");
831 }
832
833 #[test]
834 fn inequality() {
835 assert!( zc("gg0123abcd_0123456789") <
836 zc("gg0123abcd_012345678a") );
837
838 assert!( zc("gg0123abcd") <
839 zc("gg0123abcd_012345678a") );
840 }
841
842 #[test]
843 fn incdec() {
844 use core::cmp::Ordering::{Greater,Less};
845 impl Mutable {
846 fn tincdec<ASO:AddSubOffset>(mut self, exp: &str, aso: ASO,
847 exp_ord: Ordering) -> Self {
848 let before = self.repack().unwrap();
849 let got = self.addsub(&aso).unwrap();
850 assert_eq!(got.to_string(), exp);
851 assert_eq!(got.cmp(&before), exp_ord);
852
853 fn h(z: &ZCoord) -> u64 {
854 let mut h = DefaultHasher::new();
855 z.hash(&mut h);
856 h.finish()
857 }
858 assert_ne!(h(&got), h(&before));
859 self
860 }
861 fn tinc(self, e: &str) -> Self { self.tincdec(e, Increment, Greater) }
862 fn tdec(self, e: &str) -> Self { self.tincdec(e, Decrement, Less) }
863 }
864 let start: ZCoord = default();
865 assert_eq!(format!("{}", &start), "g000000000");
866 start.clone_mut()
867 .tinc("g001000000");
868 start.clone_mut()
869 .tdec("fvvv000000");
870
871 mk("000000000a")
872 .tinc("000100000a")
873 .tinc("000200000a")
874 .tdec("000100000a")
875 .tdec("000000000a")
876 .tdec("0000000009_vvvvvvvvvv_vvvuvvvvvv")
877 .tdec("0000000009_vvvvvvvvvv_vvvtvvvvvv")
878 ;
879 mk("vvvvvvvvvv")
880 .tinc("vvvvvvvvvv_0000000000_0001000000")
881 .tdec("vvvvvvvvvv")
882 ;
883 mk("vvvvvvvvvv_vvvvvvvvvv_vvvvv01234")
884 .tinc("vvvvvvvvvv_vvvvvvvvvv_vvvvv01234_0000000000_0001000000")
885 ;
886 mk("0000000000_0000000000_0001012340")
887 .tdec("0000000000_0000000000_0000012340")
888 .tdec("0000000000_0000000000_000001233v_vvvvvvvvvv_vvvuvvvvvv")
889 ;
890
891 mk("vvvvvvvvvv")
892 .tinc("vvvvvvvvvv_0000000000_0001000000")
893 ;
894 mk("vvvvvvvvvv_vvvvvvvvvv_vvvvv01234")
895 .tinc("vvvvvvvvvv_vvvvvvvvvv_vvvvv01234_0000000000_0001000000")
896 ;
897
898 assert_eq!( Mutable::some_range(Some(&mk("0200000000")),
899 Some(&mk("0100000000")),
900 1).unwrap_err(),
901 LogicError::from(RangeImpossible::Backwards) );
902
903 assert_eq!( Mutable::some_range(Some(&mk("0200000000")),
904 Some(&mk("0200000000")),
905 1).unwrap_err(),
906 LogicError::from(RangeImpossible::Empty) );
907 }
908
909 #[test]
910 fn iter() {
911 let mut m = mk("000000000a").iter(Increment);
912 assert_eq!( m.next(), Some(zc("000100000a")) );
913 assert_eq!( m.next(), Some(zc("000200000a")) );
914
915 let mut m = mk("000000000a").iter(Decrement);
916 assert_eq!( m.next(), Some(zc("0000000009_vvvvvvvvvv_vvvuvvvvvv")) );
917 assert_eq!( m.next(), Some(zc("0000000009_vvvvvvvvvv_vvvtvvvvvv")) );
918 }
919
920 #[test]
921 fn range() {
922 struct It {
923 i: RangeIterator,
924 last: ZCoord,
925 }
926 impl It {
927 fn new(x: &str, y: &str, count: u32) -> Self {
928 let x = mk(x);
929 let y = mk(y);
930 let i = x.range_upto(&y, count).unwrap();
931 It { i, last: x.repack().unwrap() }
932 }
933 fn nxt(&mut self, exp: &str) {
934 let got = self.i.next().unwrap();
935 assert_eq!(got.to_string(), exp);
936 assert_eq!(got, zc(exp));
937 assert!(got > self.last, "{:?} <= {:?} !", &got, &self.last);
938 self.last = got.clone();
939 }
940 }
941 let mut it = It::new("3333333333_vvvvvvvvv0",
942 "3333333334_0000000040", 4);
943 it.nxt("3333333334");
944 it.nxt("3333333334_0000000010");
945 it.nxt("3333333334_0000000020");
946 it.nxt("3333333334_0000000030");
947 assert_eq!(it.i.next(), None);
948
949 let mut it = It::new("3333333333_vvvvvvvvo0",
950 "3333333334_0000000030", 4);
951 it.nxt("3333333333_vvvvvvvvq6");
952 it.nxt("3333333333_vvvvvvvvsc");
953 it.nxt("3333333333_vvvvvvvvui");
954 it.nxt("3333333334_000000000o");
955 assert_eq!(it.i.next(), None);
956
957 let mut it = It::new("aaaaaaaaaa_vvvvvvvvvv",
958 "aaaaaaaaab" , 2);
959 it.nxt("aaaaaaaaaa_vvvvvvvvvv_alalalalal");
960 it.nxt("aaaaaaaaaa_vvvvvvvvvv_lalalalala");
961 assert_eq!(it.i.next(), None);
962
963 let mut it = It::new("1000000000",
964 "2000000000", 3);
965 it.nxt("1800000000");
966 it.nxt("1g00000000");
967 it.nxt("1o00000000");
968 assert_eq!(it.i.next(), None);
969
970 assert_eq!(mk ("aaaaaaaaaa_vvvvvvvvvv")
971 .range_upto(&mk("aaaaaaaaaa_vvvvvvvvvv"), 4)
972 .unwrap_err(),
973 RangeImpossible::Empty);
974
975 assert_eq!(mk ("0000000001")
976 .range_upto(&mk("0000000001"), 4)
977 .unwrap_err(),
978 RangeImpossible::Empty);
979
980 assert_eq!(mk ("0000000002")
981 .range_upto(&mk("0000000001"), 4)
982 .unwrap_err(),
983 RangeImpossible::Backwards);
984 }
985
986 #[test]
987 fn some_range() {
988 struct It {
989 i: BoxedIterator,
990 last: Option<ZCoord>,
991 }
992 #[throws(LogicError)]
993 fn mkr(a: Option<&str>, b: Option<&str>, count: RangeCount) -> It {
994 let a = a.map(|s: &str| s.parse::<ZCoord>().unwrap().clone_mut());
995 let b = b.map(|s: &str| s.parse::<ZCoord>().unwrap().clone_mut());
996 let last = a.as_ref().map(|m| m.repack().unwrap());
997 let i = Mutable::some_range(a.as_ref(), b.as_ref(), count)?;
998 It { i, last }
999 }
1000 impl It {
1001 fn nxt(&mut self, exp: Option<&str>) {
1002 let got = self.i.next();
1003 let got_s = got.as_ref().map(|s| s.to_string());
1004 let got_s = got_s.as_ref().map(|s| s.as_str());
1005 assert_eq!(got_s, exp);
1006 if let (Some(got), Some(exp)) = (&got, &exp) {
1007 assert_eq!(got, &zc(exp));
1008 if let Some(last) = &self.last { assert!(got > last); }
1009 }
1010 self.last = got.clone();
1011 }
1012 }
1013 let mut it = mkr(Some("3000000000"),Some("4000000000"),3).unwrap();
1014 it.nxt(Some("3800000000"));
1015 it.nxt(Some("3g00000000"));
1016 it.nxt(Some("3o00000000"));
1017 it.nxt(None);
1018 let mut it = mkr(Some("3000000000"),Some("4000000000"),1).unwrap();
1019 it.nxt(Some("3g00000000"));
1020 it.nxt(None);
1021 let mut it = mkr(None, Some("4000000000"),2).unwrap();
1022 it.nxt(Some("3vvv000000"));
1023 it.nxt(Some("3vvvg00000"));
1024 it.nxt(None);
1025 let mut it = mkr(Some("4000000000"),None,2).unwrap();
1026 it.nxt(Some("4001000000"));
1027 it.nxt(Some("4002000000"));
1028 it.nxt(None);
1029 let x = mkr(None,None,2);
1030 assert_eq!( x.err(), Some(
1031 LogicError::RangeTotallyUnbounded(TotallyUnboundedRange)
1032 ));
1033 let mut it = mkr(Some("fvvq000000"),Some("g026000000"),1).unwrap();
1034 it.nxt(Some("g010000000"));
1035 it.nxt(None);
1036 let mut it = mkr(None,Some("fvvq000000"),0).unwrap();
1037 it.nxt(None);
1038
1039 let mut it = mkr(Some("g0h8000000"),
1040 Some("g0h8000000_0000004000"), 2) .unwrap();
1041 it.nxt(Some("g0h8000000_0000001ala"));
1042 it.nxt(Some("g0h8000000_0000002lak"));
1043 it.nxt(None);
1044
1045 let mut it = mkr(None, Some("g0h8000000"), 0).unwrap();
1046 it.nxt(None);
1047 }
1048
1049 #[test]
1050 fn plus_offset() {
1051 fn chk(off: u32, s: &str) {
1052 let z: ZCoord = "3o00000000".parse().unwrap();
1053 let p = z.plus_offset(off).unwrap();
1054 assert_eq!(s, format!("{}", &p));
1055 assert_eq!(p, s.parse().unwrap());
1056 }
1057
1058 chk( 0, "3o00000000_0000004000");
1059 chk( 1, "3o00000000_000000c000");
1060 chk(0xffffffff, "3o00000000_vvvvvvs000");
1061 }
1062}