any_rope/lib.rs
1#![allow(
2 incomplete_features,
3 clippy::arc_with_non_send_sync,
4 clippy::too_many_arguments
5)]
6#![feature(generic_const_exprs)]
7//! AnyRope is an arbitrary data rope for Rust.
8//!
9//! AnyRope's [`Rope<M>`] contains elements `M` that implement [`Measurable`], a
10//! trait that assigns an arbitrary "measure" to each element, through the
11//! [`measure()`][Measurable::measure] function. AnyRope can then use these
12//! "measures" to retrieve and iterate over elements in any given "measure" from
13//! the beginning of the [`Rope<M>`].
14//!
15//! Keep in mind that the "measure" does not correspond to the actual size of a
16//! type in bits or bytes, but is instead decided by the implementor, and can be
17//! whatever value they want.
18//!
19//! The library is made up of four main components:
20//!
21//! - [`Rope<M>`]: the main rope type.
22//! - [`RopeSlice<M>`]: an immutable view into part of a [`Rope<M>`].
23//! - [`iter`]: iterators over [`Rope<M>`]/[`RopeSlice<M>`] data.
24//! - [`RopeBuilder<M>`]: an efficient incremental [`Rope<M>`] builder.
25//!
26//! # A Basic Example
27//!
28//! Let's say we want create a tagging system that will be applied to text,
29//! in which the tags either tell you to print normally, print in red,
30//! underline, or skip:
31//!
32//! ```rust
33//! #![feature(generic_const_exprs)]
34//! # use std::io::Result;
35//! use std::fs::File;
36//! use std::io::{BufReader, BufWriter};
37//! use any_rope::{Rope, Measurable};
38//!
39//! // A simple tag structure that our program can understand.
40//! #[derive(Clone, Copy, PartialEq, Eq)]
41//! enum Tag {
42//! InRed,
43//! UnderLine,
44//! Normal,
45//! // The `usize` in here represents an amount of characters that won't change
46//! // the color of the text.
47//! Skip(usize)
48//! }
49//!
50//! impl Measurable for Tag {
51//! type Measure = usize;
52//!
53//! fn measure(&self) -> Self::Measure {
54//! match self {
55//! // The coloring tags are only meant to color, not to "move forward".
56//! Tag::InRed | Tag::UnderLine | Tag::Normal => 0,
57//! // The Skip tag represents an amount of characters in which no
58//! // tags are applied.
59//! Tag::Skip(amount) => *amount
60//! }
61//! }
62//! }
63//! use Tag::*;
64//!
65//! # fn activate_tag(tag: &Tag) {}
66//! // An `&str` that will be colored.
67//! let my_str = "This word will be red!";
68//!
69//! // Here's what this means:
70//! // - Skip 5 characters;
71//! // - Change the color to red;
72//! // - Start underlining;
73//! // - Skip 4 characters;
74//! // - Change the rendering back to normal.
75//! let my_tagger = Rope::from_slice(&[Skip(5), InRed, UnderLine, Skip(4), Normal]);
76//! // Do note that Tag::Skip only represents characters because we are also iterating
77//! // over a `Chars` iterator, and have chosen to do so.
78//!
79//! let mut tags_iter = my_tagger.iter().peekable();
80//! for (cur_index, ch) in my_str.chars().enumerate() {
81//! // The while let loop here is a useful way to activate all tags within the same
82//! // character. Note the sequence of [.., InRed, UnderLine, ..], both of which have
83//! // a measure of 0. This means that both would be triggered before moving on to the next
84//! // character.
85//! while let Some((index, tag)) = tags_iter.peek() {
86//! // The returned index is always the measure where an element began. In this
87//! // case, `tags_iter.peek()` would return `Some((0, Skip(5)))`, and then
88//! // `Some((5, InRed))`.
89//! if *index == cur_index {
90//! activate_tag(tag);
91//! tags_iter.next();
92//! } else {
93//! break;
94//! }
95//! }
96//!
97//! print!("{}", ch);
98//! }
99//! ```
100//!
101//! An example can be found in the `examples` directory, detailing a "search and
102//! replace" functionality for [`Rope<M>`].
103//!
104//! # Low-level APIs
105//!
106//! AnyRope also provides access to some of its low-level APIs, enabling client
107//! code to efficiently work with a [`Rope<M>`]'s data and implement new
108//! functionality. The most important of those API's are:
109//!
110//! - The [`chunk_at_*()`][Rope::chunk_at_measure] chunk-fetching methods of
111//! [`Rope<M>`] and [`RopeSlice<M>`].
112//! - The [`Chunks`](iter::Chunks) iterator.
113//! - The functions in `slice_utils` for operating on [`&[M]`][Measurable]
114//! slices.
115//!
116//! As a reminder, if you notice similarities with the AnyRope crate, it is
117//! because this is a heavily modified fork of it.
118#![allow(
119 clippy::collapsible_if,
120 clippy::inline_always,
121 clippy::needless_return,
122 clippy::redundant_field_names,
123 clippy::type_complexity
124)]
125
126mod rope;
127mod rope_builder;
128mod slice;
129mod slice_utils;
130mod tree;
131
132pub mod iter;
133
134use std::{
135 cmp::Ordering,
136 fmt::Debug,
137 ops::{Add, Bound, Range, RangeFrom, RangeFull, RangeTo, Sub},
138};
139
140pub use crate::{
141 rope::Rope,
142 rope_builder::RopeBuilder,
143 slice::RopeSlice,
144 tree::{max_children, max_len},
145};
146
147/// A trait defining a comparison that must panic if there is ever ambiguity
148/// about the ordering in a given struct.
149pub trait FallibleOrd {
150 /// A comparison that can panic.
151 ///
152 /// This comparison should panic with the [`unreachable!`] macro, since the
153 /// panicking code is supposed to be unreachable from within `any-rope`.
154 ///
155 /// Here's an example of how this function should be implemented:
156 ///
157 /// ```rust
158 /// # use std::cmp::Ordering;
159 /// # use any_rope::FallibleOrd;
160 /// struct TwoUsizes(usize, usize);
161 ///
162 /// impl FallibleOrd for TwoUsizes {
163 /// fn fallible_cmp(&self, other: &Self) -> Ordering {
164 /// use Ordering::*;
165 /// let cmp_0 = self.0.cmp(&other.0);
166 /// let cmp_1 = self.1.cmp(&other.1);
167 ///
168 /// match (cmp_0, cmp_1) {
169 /// (Less, Less) => Less,
170 /// (Less, Equal) => Less,
171 /// (Equal, Less) => Less,
172 /// (Equal, Equal) => Equal,
173 /// (Equal, Greater) => Greater,
174 /// (Greater, Equal) => Greater,
175 /// (Greater, Greater) => todo!(),
176 /// (Less, Greater) | (Greater, Less) => unreachable!(
177 /// "Ambiguous comparison, report this as a bug on the \
178 /// AnyRope crate"
179 /// ),
180 /// }
181 /// }
182 /// }
183 /// ```
184 ///
185 /// Note that, if all values are equal, then the comparison is equal. If at
186 /// least one value is greater or lesse, then the comparison follows that
187 /// value. But if there are greater and lesser values at the same time, then
188 /// something has failed within `any-rope` itself, and that should be
189 /// reported as a bug.
190 fn fallible_cmp(&self, other: &Self) -> Ordering;
191}
192
193/// A object that has a user defined size, that can be interpreted by a
194/// [`Rope<M>`].
195pub trait Measurable: Clone {
196 /// This type is what will be used to query, iterate, modify, and slice up
197 /// the [`Rope`].
198 ///
199 /// It needs to be light, since it will be heavily utilized from within
200 /// `any-rope`, and needs to be malleable, such that it can be compared,
201 /// added and subtracted at will by the rope.
202 ///
203 /// Normally, in order to query, iterate, or modify the rope, the various
204 /// methods take in a comparator function. This function offers flexibility
205 /// in how one searches within the rope, for example:
206 ///
207 /// ```rust
208 /// # use std::{
209 /// # cmp::Ordering,
210 /// # ops::{Add, Sub},
211 /// # };
212 /// # use any_rope::{FallibleOrd, Measurable, Rope};
213 /// #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
214 /// struct TwoWidths(usize, usize);
215 ///
216 /// impl TwoWidths {
217 /// fn first_cmp(&self, other: &Self) -> Ordering {
218 /// self.0.cmp(&other.0)
219 /// }
220 ///
221 /// fn second_cmp(&self, other: &Self) -> Ordering {
222 /// self.1.cmp(&other.1)
223 /// }
224 /// }
225 ///
226 /// impl FallibleOrd for TwoWidths {
227 /// fn fallible_cmp(&self, other: &Self) -> Ordering {
228 /// use Ordering::*;
229 /// let cmp_0 = self.0.cmp(&other.0);
230 /// let cmp_1 = self.1.cmp(&other.1);
231 ///
232 /// match (cmp_0, cmp_1) {
233 /// (Less, Less) => Less,
234 /// (Less, Equal) => Less,
235 /// (Equal, Less) => Less,
236 /// (Equal, Equal) => Equal,
237 /// (Equal, Greater) => Greater,
238 /// (Greater, Equal) => Greater,
239 /// (Greater, Greater) => todo!(),
240 /// (Less, Greater) | (Greater, Less) => unreachable!(
241 /// "Ambiguous comparison, report this as a bug on the \
242 /// AnyRope crate"
243 /// ),
244 /// }
245 /// }
246 /// }
247 ///
248 /// // ... Implementation of `Add` and `Sub` for `TwoWidths`.
249 ///
250 /// # impl Add for TwoWidths {
251 /// # type Output = Self;
252 ///
253 /// # fn add(self, other: Self) -> Self::Output {
254 /// # Self(self.0 + other.0, self.1 + other.1)
255 /// # }
256 /// # }
257 /// # impl Sub for TwoWidths {
258 /// # type Output = Self;
259 ///
260 /// # fn sub(self, other: Self) -> Self::Output {
261 /// # Self(self.0 - other.0, self.1 - other.1)
262 /// # }
263 /// # }
264 /// #[derive(Clone, Copy, PartialEq, Eq)]
265 /// struct MyStruct(TwoWidths);
266 ///
267 /// impl Measurable for MyStruct {
268 /// type Measure = TwoWidths;
269 ///
270 /// fn measure(&self) -> Self::Measure {
271 /// self.0
272 /// }
273 /// }
274 /// ```
275 ///
276 /// With the `TwoWidths::first_cmp` and `TwoWidths::second_cmp`, you can
277 /// search with two different variables within the rope, similarly to how
278 /// regular ropes let you search by byte, char, or line.
279 ///
280 /// Note, however, that this type also requires `PartialOrd` and `Ord`. That
281 /// is because, internally, `any-rope` needs those comparison functions to
282 /// sort itself out. These implementations also cannot be derived by Rust,
283 /// and need to be
284 type Measure: Debug
285 + Default
286 + Clone
287 + Copy
288 + PartialEq
289 + Eq
290 + Add<Output = Self::Measure>
291 + Sub<Output = Self::Measure>
292 + FallibleOrd;
293
294 /// The measure of this element, it need not be the actual lenght in bytes,
295 /// but just a representative value, to be fed to the [`Rope<M>`].
296 fn measure(&self) -> Self::Measure;
297}
298
299/// A struct meant for testing and exemplification
300///
301/// Its [`measure`][Measurable::measure] is always equal to the number within.
302#[derive(Debug, Clone, Copy, PartialEq, Eq)]
303pub struct Width(pub usize);
304
305impl PartialOrd for Width {
306 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
307 Some(self.cmp(other))
308 }
309}
310
311impl Ord for Width {
312 fn cmp(&self, other: &Self) -> Ordering {
313 self.0.fallible_cmp(&other.0)
314 }
315}
316
317impl FallibleOrd for usize {
318 fn fallible_cmp(&self, other: &Self) -> Ordering {
319 self.cmp(other)
320 }
321}
322
323impl Measurable for Width {
324 type Measure = usize;
325
326 fn measure(&self) -> Self::Measure {
327 self.0
328 }
329}
330
331//==============================================================
332// Error reporting types.
333
334/// AnyRope's result type.
335pub type Result<T, M> = std::result::Result<T, Error<M>>;
336
337/// AnyRope's error type.
338#[derive(Clone, Copy)]
339#[non_exhaustive]
340pub enum Error<M: Measurable> {
341 /// Indicates that the passed index was out of bounds.
342 ///
343 /// Contains the index attempted and the actual length of the
344 /// [`Rope<M>`]/[`RopeSlice<M>`], in that order.
345 IndexOutOfBounds(usize, usize),
346
347 /// Indicates that the passed measure was out of bounds.
348 ///
349 /// Contains the index attempted and the actual measure of the
350 /// [`Rope<M>`]/[`RopeSlice<M>`], in that order.
351 MeasureOutOfBounds(M::Measure, M::Measure),
352
353 /// Indicates that a reversed index range (end < start) was encountered.
354 ///
355 /// Contains the [start, end) indices of the range, in that order.
356 IndexRangeInvalid(usize, usize),
357
358 /// Indicates that a reversed measure range (end < start) was
359 /// encountered.
360 ///
361 /// Contains the [start, end) measures of the range, in that order.
362 MeasureRangeInvalid(Option<M::Measure>, Option<M::Measure>),
363
364 /// Indicates that the passed index range was partially or fully out of
365 /// bounds.
366 ///
367 /// Contains the [start, end) indices of the range and the actual
368 /// length of the [`Rope<M>`]/[`RopeSlice<M>`], in that order.
369 /// When either the start or end are [`None`], that indicates a half-open
370 /// range.
371 IndexRangeOutOfBounds(Option<usize>, Option<usize>, usize),
372
373 /// Indicates that the passed measure range was partially or fully out of
374 /// bounds.
375 ///
376 /// Contains the [start, end) measures of the range and the actual
377 /// measure of the [`Rope<M>`]/[`RopeSlice<M>`], in that order.
378 /// When either the start or end are [`None`], that indicates a half-open
379 /// range.
380 MeasureRangeOutOfBounds(Option<M::Measure>, Option<M::Measure>, M::Measure),
381}
382
383impl<M: Measurable> std::fmt::Debug for Error<M> {
384 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
385 match *self {
386 Error::IndexOutOfBounds(index, len) => {
387 write!(
388 f,
389 "Index out of bounds: index {}, Rope/RopeSlice length {}",
390 index, len
391 )
392 }
393 Error::MeasureOutOfBounds(measure, max) => {
394 write!(
395 f,
396 "Measure out of bounds: measure {:?}, Rope/RopeSlice measure {:?}",
397 measure, max
398 )
399 }
400 Error::IndexRangeInvalid(start_index, end_index) => {
401 write!(
402 f,
403 "Invalid index range {}..{}: start must be <= end",
404 start_index, end_index
405 )
406 }
407 Error::MeasureRangeInvalid(start_measure, end_measure) => {
408 write!(
409 f,
410 "Invalid measure range {:?}..{:?}: start must be <= end",
411 start_measure, end_measure
412 )
413 }
414 Error::IndexRangeOutOfBounds(start, end, len) => {
415 write!(f, "Index range out of bounds: index range ")?;
416 write_range(f, start, end)?;
417 write!(f, ", Rope/RopeSlice byte length {}", len)
418 }
419 Error::MeasureRangeOutOfBounds(start, end, measure) => {
420 write!(f, "Measure range out of bounds: measure range ")?;
421 write_range(f, start, end)?;
422 write!(f, ", Rope/RopeSlice measure {:?}", measure)
423 }
424 }
425 }
426}
427
428impl<M: Measurable> std::error::Error for Error<M> {}
429
430impl<M: Measurable> std::fmt::Display for Error<M> {
431 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
432 // Just re-use the debug impl.
433 std::fmt::Debug::fmt(self, f)
434 }
435}
436
437fn write_range<T: Debug>(
438 f: &mut std::fmt::Formatter<'_>,
439 start_idx: Option<T>,
440 end_idx: Option<T>,
441) -> std::fmt::Result {
442 match (start_idx, end_idx) {
443 (None, None) => write!(f, ".."),
444 (None, Some(end)) => write!(f, "..{:?}", end),
445 (Some(start), None) => write!(f, "{:?}..", start),
446 (Some(start), Some(end)) => write!(f, "{:?}..{:?}", start, end),
447 }
448}
449
450//==============================================================
451// Range handling utilities.
452
453#[inline(always)]
454fn start_bound_to_num(b: Bound<&usize>) -> Option<usize> {
455 match b {
456 Bound::Included(n) => Some(*n),
457 Bound::Excluded(n) => Some(*n + 1),
458 Bound::Unbounded => None,
459 }
460}
461
462#[inline(always)]
463fn end_bound_to_num(b: Bound<&usize>) -> Option<usize> {
464 match b {
465 Bound::Included(n) => Some(*n + 1),
466 Bound::Excluded(n) => Some(*n),
467 Bound::Unbounded => None,
468 }
469}
470
471mod hidden {
472 use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
473
474 pub trait Internal {}
475
476 impl<T> Internal for Range<T> {}
477 impl<T> Internal for RangeFrom<T> {}
478 impl<T> Internal for RangeTo<T> {}
479 impl Internal for RangeFull {}
480}
481
482pub trait MeasureRange<M: Measurable>: hidden::Internal {
483 fn start_bound(&self) -> Option<&M::Measure>;
484
485 fn end_bound(&self) -> Option<&M::Measure>;
486}
487
488impl<M: Measurable> MeasureRange<M> for Range<M::Measure> {
489 fn start_bound(&self) -> Option<&M::Measure> {
490 Some(&self.start)
491 }
492
493 fn end_bound(&self) -> Option<&M::Measure> {
494 Some(&self.end)
495 }
496}
497
498impl<M: Measurable> MeasureRange<M> for RangeFrom<M::Measure> {
499 fn start_bound(&self) -> Option<&M::Measure> {
500 Some(&self.start)
501 }
502
503 fn end_bound(&self) -> Option<&M::Measure> {
504 None
505 }
506}
507
508impl<M: Measurable> MeasureRange<M> for RangeTo<M::Measure> {
509 fn start_bound(&self) -> Option<&M::Measure> {
510 None
511 }
512
513 fn end_bound(&self) -> Option<&M::Measure> {
514 Some(&self.end)
515 }
516}
517
518impl<M: Measurable> MeasureRange<M> for RangeFull {
519 fn start_bound(&self) -> Option<&M::Measure> {
520 None
521 }
522
523 fn end_bound(&self) -> Option<&M::Measure> {
524 None
525 }
526}
527
528#[inline(always)]
529fn measures_from_range<M: Measurable>(
530 range: &impl MeasureRange<M>,
531 limit: M::Measure,
532) -> Result<(M::Measure, M::Measure), M> {
533 #[cfg(debug_assertions)]
534 {
535 if let Some(start) = range.start_bound() {
536 assert_default_is_lowest::<M>(start);
537 }
538 if let Some(end) = range.end_bound() {
539 assert_default_is_lowest::<M>(end);
540 }
541 }
542
543 match (range.start_bound(), range.end_bound()) {
544 (None, None) => Ok((M::Measure::default(), limit)),
545 (None, Some(end)) => {
546 if end.fallible_cmp(&limit).is_gt() {
547 Err(Error::MeasureRangeOutOfBounds(None, Some(*end), limit))
548 } else {
549 Ok((M::Measure::default(), *end))
550 }
551 }
552 (Some(start), None) => {
553 if start.fallible_cmp(&limit).is_gt() {
554 Err(Error::MeasureRangeOutOfBounds(Some(*start), None, limit))
555 } else {
556 Ok((*start, limit))
557 }
558 }
559
560 (Some(start), Some(end)) => {
561 if start.fallible_cmp(end).is_gt() {
562 Err(Error::MeasureRangeInvalid(Some(*start), Some(*end)))
563 } else if end.fallible_cmp(&limit).is_gt() || start.fallible_cmp(&limit).is_gt() {
564 Err(Error::MeasureRangeOutOfBounds(
565 Some(*start),
566 Some(*end),
567 limit,
568 ))
569 } else {
570 Ok((*start, *end))
571 }
572 }
573 }
574}
575
576//==============================================================
577// Other utilities.
578
579fn assert_default_is_lowest<M: Measurable>(cmp: &M::Measure) {
580 assert!(
581 M::Measure::default().fallible_cmp(cmp).is_le(),
582 "{:?} (Measure::default()) is supposed to be the smallest possible value for \
583 Measurable::Measure, and yet {:?} is smaller",
584 M::Measure::default(),
585 cmp
586 )
587}
588
589fn fallible_saturating_sub<T>(lhs: T, rhs: T) -> T
590where
591 T: Default + FallibleOrd + Sub<Output = T>,
592{
593 if lhs.fallible_cmp(&rhs).is_le() {
594 T::default()
595 } else {
596 lhs - rhs
597 }
598}
599
600fn fallible_min<T: FallibleOrd>(lhs: T, rhs: T) -> T {
601 if lhs.fallible_cmp(&rhs).is_le() {
602 lhs
603 } else {
604 rhs
605 }
606}
607
608fn fallible_max<T: FallibleOrd>(lhs: T, rhs: T) -> T {
609 if lhs.fallible_cmp(&rhs).is_ge() {
610 lhs
611 } else {
612 rhs
613 }
614}