logiguard fork v3: full patch set on verified 8c74db0 tree
Includes prior-session patches (carry forward so the app compiles): - crates/gpui/build.rs: cross-compile manifest fix - crates/gpui/src/platform.rs: PlatformWindow::activate_with_token trait method - crates/gpui/src/window.rs: Window::activate_with_token public API - crates/gpui_linux/src/linux/wayland/window.rs: WaylandWindow::activate_with_token + activate() keyboard-serial fix Plus the focus-serial fix: - serial.rs: SerialKind::KeyboardEnter - client.rs: store wl_keyboard.enter serial; latest_serial_of() Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
37
crates/rope/Cargo.toml
Normal file
37
crates/rope/Cargo.toml
Normal file
@@ -0,0 +1,37 @@
|
||||
[package]
|
||||
name = "rope"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/rope.rs"
|
||||
|
||||
[dependencies]
|
||||
heapless.workspace = true
|
||||
log.workspace = true
|
||||
rayon.workspace = true
|
||||
sum_tree.workspace = true
|
||||
unicode-segmentation.workspace = true
|
||||
util.workspace = true
|
||||
ztracing.workspace = true
|
||||
tracing.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
ctor.workspace = true
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
rand.workspace = true
|
||||
util = { workspace = true, features = ["test-support"] }
|
||||
criterion.workspace = true
|
||||
zlog.workspace = true
|
||||
|
||||
[[bench]]
|
||||
name = "rope_benchmark"
|
||||
harness = false
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = ["tracing"]
|
||||
1
crates/rope/LICENSE-GPL
Symbolic link
1
crates/rope/LICENSE-GPL
Symbolic link
@@ -0,0 +1 @@
|
||||
../../LICENSE-GPL
|
||||
273
crates/rope/benches/rope_benchmark.rs
Normal file
273
crates/rope/benches/rope_benchmark.rs
Normal file
@@ -0,0 +1,273 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use criterion::{
|
||||
BatchSize, BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main,
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use rand::rngs::StdRng;
|
||||
use rope::{Point, Rope};
|
||||
use sum_tree::Bias;
|
||||
use util::RandomCharIter;
|
||||
|
||||
/// Returns a biased random string whose UTF-8 length is close to but no more than `len` bytes.
|
||||
///
|
||||
/// The string is biased towards characters expected to occur in text or likely to exercise edge
|
||||
/// cases.
|
||||
fn generate_random_text(rng: &mut StdRng, len: usize) -> String {
|
||||
let mut str = String::with_capacity(len);
|
||||
let mut chars = RandomCharIter::new(rng);
|
||||
loop {
|
||||
let ch = chars.next().unwrap();
|
||||
if str.len() + ch.len_utf8() > len {
|
||||
break;
|
||||
}
|
||||
str.push(ch);
|
||||
}
|
||||
str
|
||||
}
|
||||
|
||||
fn generate_random_rope(rng: &mut StdRng, text_len: usize) -> Rope {
|
||||
let text = generate_random_text(rng, text_len);
|
||||
let mut rope = Rope::new();
|
||||
rope.push(&text);
|
||||
rope
|
||||
}
|
||||
|
||||
fn generate_random_rope_ranges(rng: &mut StdRng, rope: &Rope) -> Vec<Range<usize>> {
|
||||
let range_max_len = 50;
|
||||
let num_ranges = rope.len() / range_max_len;
|
||||
|
||||
let mut ranges = Vec::new();
|
||||
let mut start = 0;
|
||||
for _ in 0..num_ranges {
|
||||
let range_start = rope.clip_offset(
|
||||
rng.random_range(start..=(start + range_max_len)),
|
||||
sum_tree::Bias::Left,
|
||||
);
|
||||
let range_end = rope.clip_offset(
|
||||
rng.random_range(range_start..(range_start + range_max_len)),
|
||||
sum_tree::Bias::Right,
|
||||
);
|
||||
|
||||
let range = range_start..range_end;
|
||||
if !range.is_empty() {
|
||||
ranges.push(range);
|
||||
}
|
||||
|
||||
start = range_end + 1;
|
||||
}
|
||||
|
||||
ranges
|
||||
}
|
||||
|
||||
fn generate_random_rope_points(rng: &mut StdRng, rope: &Rope) -> Vec<Point> {
|
||||
let num_points = rope.len() / 10;
|
||||
|
||||
let mut points = Vec::new();
|
||||
for _ in 0..num_points {
|
||||
points.push(rope.offset_to_point(rng.random_range(0..rope.len())));
|
||||
}
|
||||
points
|
||||
}
|
||||
|
||||
fn rope_benchmarks(c: &mut Criterion) {
|
||||
static SEED: u64 = 9999;
|
||||
static KB: usize = 1024;
|
||||
|
||||
let sizes = [4 * KB, 64 * KB];
|
||||
|
||||
let mut group = c.benchmark_group("push");
|
||||
for size in sizes.iter() {
|
||||
group.throughput(Throughput::Bytes(*size as u64));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
|
||||
let mut rng = StdRng::seed_from_u64(SEED);
|
||||
let text = generate_random_text(&mut rng, *size);
|
||||
|
||||
b.iter(|| {
|
||||
let mut rope = Rope::new();
|
||||
for _ in 0..10 {
|
||||
rope.push(&text);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
|
||||
let mut group = c.benchmark_group("append");
|
||||
for size in sizes.iter() {
|
||||
group.throughput(Throughput::Bytes(*size as u64));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
|
||||
let mut rng = StdRng::seed_from_u64(SEED);
|
||||
let mut random_ropes = Vec::new();
|
||||
for _ in 0..5 {
|
||||
let rope = generate_random_rope(&mut rng, *size);
|
||||
random_ropes.push(rope);
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
let mut rope_b = Rope::new();
|
||||
for rope in &random_ropes {
|
||||
rope_b.append(rope.clone())
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
|
||||
let mut group = c.benchmark_group("slice");
|
||||
for size in sizes.iter() {
|
||||
group.throughput(Throughput::Bytes(*size as u64));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
|
||||
let mut rng = StdRng::seed_from_u64(SEED);
|
||||
let rope = generate_random_rope(&mut rng, *size);
|
||||
|
||||
b.iter_batched(
|
||||
|| generate_random_rope_ranges(&mut rng, &rope),
|
||||
|ranges| {
|
||||
for range in ranges.iter() {
|
||||
rope.slice(range.clone());
|
||||
}
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
|
||||
let mut group = c.benchmark_group("bytes_in_range");
|
||||
for size in sizes.iter() {
|
||||
group.throughput(Throughput::Bytes(*size as u64));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
|
||||
let mut rng = StdRng::seed_from_u64(SEED);
|
||||
let rope = generate_random_rope(&mut rng, *size);
|
||||
|
||||
b.iter_batched(
|
||||
|| generate_random_rope_ranges(&mut rng, &rope),
|
||||
|ranges| {
|
||||
for range in ranges.iter() {
|
||||
let bytes = rope.bytes_in_range(range.clone());
|
||||
assert!(bytes.into_iter().count() > 0);
|
||||
}
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
|
||||
let mut group = c.benchmark_group("chars");
|
||||
for size in sizes.iter() {
|
||||
group.throughput(Throughput::Bytes(*size as u64));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
|
||||
let mut rng = StdRng::seed_from_u64(SEED);
|
||||
let rope = generate_random_rope(&mut rng, *size);
|
||||
|
||||
b.iter(|| {
|
||||
let chars = rope.chars().count();
|
||||
assert!(chars > 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
|
||||
let mut group = c.benchmark_group("clip_point");
|
||||
for size in sizes.iter() {
|
||||
group.throughput(Throughput::Bytes(*size as u64));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
|
||||
let mut rng = StdRng::seed_from_u64(SEED);
|
||||
let rope = generate_random_rope(&mut rng, *size);
|
||||
|
||||
b.iter_batched(
|
||||
|| generate_random_rope_points(&mut rng, &rope),
|
||||
|offsets| {
|
||||
for offset in offsets.iter() {
|
||||
black_box(rope.clip_point(*offset, Bias::Left));
|
||||
black_box(rope.clip_point(*offset, Bias::Right));
|
||||
}
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
|
||||
let mut group = c.benchmark_group("point_to_offset");
|
||||
for size in sizes.iter() {
|
||||
group.throughput(Throughput::Bytes(*size as u64));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
|
||||
let mut rng = StdRng::seed_from_u64(SEED);
|
||||
let rope = generate_random_rope(&mut rng, *size);
|
||||
|
||||
b.iter_batched(
|
||||
|| generate_random_rope_points(&mut rng, &rope),
|
||||
|offsets| {
|
||||
for offset in offsets.iter() {
|
||||
black_box(rope.point_to_offset(*offset));
|
||||
}
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
|
||||
let mut group = c.benchmark_group("cursor");
|
||||
for size in sizes.iter() {
|
||||
group.throughput(Throughput::Bytes(*size as u64));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
|
||||
let mut rng = StdRng::seed_from_u64(SEED);
|
||||
let rope = generate_random_rope(&mut rng, *size);
|
||||
|
||||
b.iter_batched(
|
||||
|| {
|
||||
let num_points = rope.len() / 10;
|
||||
|
||||
let mut points = Vec::new();
|
||||
for _ in 0..num_points {
|
||||
points.push(rng.random_range(0..rope.len()));
|
||||
}
|
||||
points
|
||||
},
|
||||
|offsets| {
|
||||
for offset in offsets.iter() {
|
||||
black_box(rope.cursor(*offset));
|
||||
}
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
);
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
|
||||
let mut group = c.benchmark_group("append many");
|
||||
group.throughput(Throughput::Bytes(128 * 100_000));
|
||||
|
||||
group.bench_function("small to large", |b| {
|
||||
b.iter(|| {
|
||||
let mut rope = Rope::new();
|
||||
let small = Rope::from("A".repeat(128));
|
||||
for _ in 0..100_000 {
|
||||
rope.append(small.clone());
|
||||
}
|
||||
assert_eq!(rope.len(), 128 * 100_000);
|
||||
});
|
||||
});
|
||||
|
||||
group.bench_function("large to small", |b| {
|
||||
b.iter(|| {
|
||||
let mut rope = Rope::new();
|
||||
let small = Rope::from("A".repeat(128));
|
||||
for _ in 0..100_000 {
|
||||
let large = rope;
|
||||
rope = small.clone();
|
||||
rope.append(large);
|
||||
}
|
||||
assert_eq!(rope.len(), 128 * 100_000);
|
||||
});
|
||||
});
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, rope_benchmarks);
|
||||
criterion_main!(benches);
|
||||
1249
crates/rope/src/chunk.rs
Normal file
1249
crates/rope/src/chunk.rs
Normal file
File diff suppressed because it is too large
Load Diff
49
crates/rope/src/offset_utf16.rs
Normal file
49
crates/rope/src/offset_utf16.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use std::ops::{Add, AddAssign, Sub};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub struct OffsetUtf16(pub usize);
|
||||
|
||||
impl<'a> Add<&'a Self> for OffsetUtf16 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: &'a Self) -> Self::Output {
|
||||
Self(self.0 + other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for OffsetUtf16 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
Self(self.0 + other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Sub<&'a Self> for OffsetUtf16 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: &'a Self) -> Self::Output {
|
||||
debug_assert!(*other <= self);
|
||||
Self(self.0 - other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for OffsetUtf16 {
|
||||
type Output = OffsetUtf16;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Self(self.0 - other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AddAssign<&'a Self> for OffsetUtf16 {
|
||||
fn add_assign(&mut self, other: &'a Self) {
|
||||
self.0 += other.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Self> for OffsetUtf16 {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
self.0 += other.0;
|
||||
}
|
||||
}
|
||||
146
crates/rope/src/point.rs
Normal file
146
crates/rope/src/point.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::{self, Debug},
|
||||
ops::{Add, AddAssign, Range, Sub},
|
||||
};
|
||||
|
||||
/// A zero-indexed point in a text buffer consisting of a row and column.
|
||||
#[derive(Clone, Copy, Default, Eq, PartialEq, Hash)]
|
||||
pub struct Point {
|
||||
pub row: u32,
|
||||
pub column: u32,
|
||||
}
|
||||
|
||||
impl Debug for Point {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Point({}:{})", self.row, self.column)
|
||||
}
|
||||
}
|
||||
|
||||
impl Point {
|
||||
pub const MAX: Self = Self {
|
||||
row: u32::MAX,
|
||||
column: u32::MAX,
|
||||
};
|
||||
|
||||
pub fn new(row: u32, column: u32) -> Self {
|
||||
Point { row, column }
|
||||
}
|
||||
|
||||
pub fn row_range(range: Range<u32>) -> Range<Self> {
|
||||
Point {
|
||||
row: range.start,
|
||||
column: 0,
|
||||
}..Point {
|
||||
row: range.end,
|
||||
column: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Point::new(0, 0)
|
||||
}
|
||||
|
||||
pub fn parse_str(s: &str) -> Self {
|
||||
let mut point = Self::zero();
|
||||
for (row, line) in s.split('\n').enumerate() {
|
||||
point.row = row as u32;
|
||||
point.column = line.len() as u32;
|
||||
}
|
||||
point
|
||||
}
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.row == 0 && self.column == 0
|
||||
}
|
||||
|
||||
pub fn saturating_sub(self, other: Self) -> Self {
|
||||
if self < other {
|
||||
Self::zero()
|
||||
} else {
|
||||
self - other
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<&'a Self> for Point {
|
||||
type Output = Point;
|
||||
|
||||
fn add(self, other: &'a Self) -> Self::Output {
|
||||
self + *other
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Point {
|
||||
type Output = Point;
|
||||
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
if other.row == 0 {
|
||||
Point::new(self.row, self.column + other.column)
|
||||
} else {
|
||||
Point::new(self.row + other.row, other.column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Sub<&'a Self> for Point {
|
||||
type Output = Point;
|
||||
|
||||
fn sub(self, other: &'a Self) -> Self::Output {
|
||||
self - *other
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Point {
|
||||
type Output = Point;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
debug_assert!(other <= self);
|
||||
|
||||
if self.row == other.row {
|
||||
Point::new(0, self.column - other.column)
|
||||
} else {
|
||||
Point::new(self.row - other.row, self.column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AddAssign<&'a Self> for Point {
|
||||
fn add_assign(&mut self, other: &'a Self) {
|
||||
*self += *other;
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Self> for Point {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
if other.row == 0 {
|
||||
self.column += other.column;
|
||||
} else {
|
||||
self.row += other.row;
|
||||
self.column = other.column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Point {
|
||||
fn partial_cmp(&self, other: &Point) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Point {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
fn cmp(&self, other: &Point) -> Ordering {
|
||||
let a = ((self.row as usize) << 32) | self.column as usize;
|
||||
let b = ((other.row as usize) << 32) | other.column as usize;
|
||||
a.cmp(&b)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
fn cmp(&self, other: &Point) -> Ordering {
|
||||
match self.row.cmp(&other.row) {
|
||||
Ordering::Equal => self.column.cmp(&other.column),
|
||||
comparison @ _ => comparison,
|
||||
}
|
||||
}
|
||||
}
|
||||
119
crates/rope/src/point_utf16.rs
Normal file
119
crates/rope/src/point_utf16.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
ops::{Add, AddAssign, Sub},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash)]
|
||||
pub struct PointUtf16 {
|
||||
pub row: u32,
|
||||
pub column: u32,
|
||||
}
|
||||
|
||||
impl PointUtf16 {
|
||||
pub const MAX: Self = Self {
|
||||
row: u32::MAX,
|
||||
column: u32::MAX,
|
||||
};
|
||||
|
||||
pub fn new(row: u32, column: u32) -> Self {
|
||||
PointUtf16 { row, column }
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
PointUtf16::new(0, 0)
|
||||
}
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.row == 0 && self.column == 0
|
||||
}
|
||||
|
||||
pub fn saturating_sub(self, other: Self) -> Self {
|
||||
if self < other {
|
||||
Self::zero()
|
||||
} else {
|
||||
self - other
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<&'a Self> for PointUtf16 {
|
||||
type Output = PointUtf16;
|
||||
|
||||
fn add(self, other: &'a Self) -> Self::Output {
|
||||
self + *other
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for PointUtf16 {
|
||||
type Output = PointUtf16;
|
||||
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
if other.row == 0 {
|
||||
PointUtf16::new(self.row, self.column + other.column)
|
||||
} else {
|
||||
PointUtf16::new(self.row + other.row, other.column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Sub<&'a Self> for PointUtf16 {
|
||||
type Output = PointUtf16;
|
||||
|
||||
fn sub(self, other: &'a Self) -> Self::Output {
|
||||
self - *other
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for PointUtf16 {
|
||||
type Output = PointUtf16;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
debug_assert!(other <= self);
|
||||
|
||||
if self.row == other.row {
|
||||
PointUtf16::new(0, self.column - other.column)
|
||||
} else {
|
||||
PointUtf16::new(self.row - other.row, self.column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AddAssign<&'a Self> for PointUtf16 {
|
||||
fn add_assign(&mut self, other: &'a Self) {
|
||||
*self += *other;
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Self> for PointUtf16 {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
if other.row == 0 {
|
||||
self.column += other.column;
|
||||
} else {
|
||||
self.row += other.row;
|
||||
self.column = other.column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for PointUtf16 {
|
||||
fn partial_cmp(&self, other: &PointUtf16) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for PointUtf16 {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
fn cmp(&self, other: &PointUtf16) -> Ordering {
|
||||
let a = ((self.row as usize) << 32) | self.column as usize;
|
||||
let b = ((other.row as usize) << 32) | other.column as usize;
|
||||
a.cmp(&b)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
fn cmp(&self, other: &PointUtf16) -> Ordering {
|
||||
match self.row.cmp(&other.row) {
|
||||
Ordering::Equal => self.column.cmp(&other.column),
|
||||
comparison @ _ => comparison,
|
||||
}
|
||||
}
|
||||
}
|
||||
2518
crates/rope/src/rope.rs
Normal file
2518
crates/rope/src/rope.rs
Normal file
File diff suppressed because it is too large
Load Diff
51
crates/rope/src/unclipped.rs
Normal file
51
crates/rope/src/unclipped.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use crate::ChunkSummary;
|
||||
use std::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Unclipped<T>(pub T);
|
||||
|
||||
impl<T> From<T> for Unclipped<T> {
|
||||
fn from(value: T) -> Self {
|
||||
Unclipped(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: sum_tree::Dimension<'a, ChunkSummary>> sum_tree::Dimension<'a, ChunkSummary>
|
||||
for Unclipped<T>
|
||||
{
|
||||
fn zero(_: ()) -> Self {
|
||||
Self(T::zero(()))
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, summary: &'a ChunkSummary, _: ()) {
|
||||
self.0.add_summary(summary, ());
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Add<T, Output = T>> Add<Unclipped<T>> for Unclipped<T> {
|
||||
type Output = Unclipped<T>;
|
||||
|
||||
fn add(self, rhs: Unclipped<T>) -> Self::Output {
|
||||
Unclipped(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sub<T, Output = T>> Sub<Unclipped<T>> for Unclipped<T> {
|
||||
type Output = Unclipped<T>;
|
||||
|
||||
fn sub(self, rhs: Unclipped<T>) -> Self::Output {
|
||||
Unclipped(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AddAssign<T>> AddAssign<Unclipped<T>> for Unclipped<T> {
|
||||
fn add_assign(&mut self, rhs: Unclipped<T>) {
|
||||
self.0 += rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SubAssign<T>> SubAssign<Unclipped<T>> for Unclipped<T> {
|
||||
fn sub_assign(&mut self, rhs: Unclipped<T>) {
|
||||
self.0 -= rhs.0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user