use super::Rope;
use super::gap_buffer::GapBuffer;
use super::metrics::ChunkSummary;
use super::rope::RopeChunk;
use super::utils::split_adjusted;
use crate::tree::TreeBuilder;
#[derive(Clone, Default)]
pub struct RopeBuilder {
tree_builder: TreeBuilder<{ Rope::arity() }, RopeChunk>,
buffer: RopeChunk,
buffer_len_left: usize,
rope_has_trailing_newline: bool,
}
#[inline]
fn gap_buffer_push_with_remainder<'a, const MAX_BYTES: usize>(
buffer: &mut GapBuffer<MAX_BYTES>,
buffer_len_left: &mut usize,
s: &'a str,
) -> Option<&'a str> {
debug_assert_eq!(buffer.len_right(), 0);
let len_left = *buffer_len_left;
let space_left = MAX_BYTES - len_left;
let (push, rest) = split_adjusted::<false>(s, space_left);
debug_assert!(push.len() <= space_left);
buffer.bytes[len_left..len_left + push.len()]
.copy_from_slice(push.as_bytes());
*buffer_len_left += push.len();
if rest.is_empty() { None } else { Some(rest) }
}
impl RopeBuilder {
#[inline]
pub fn append<T>(&mut self, text: T) -> &mut Self
where
T: AsRef<str>,
{
let mut text = text.as_ref();
while let Some(rest) = gap_buffer_push_with_remainder(
&mut self.buffer,
&mut self.buffer_len_left,
text,
) {
self.buffer.left_summary =
ChunkSummary::from(self.buffer_left_chunk());
self.tree_builder.append(core::mem::take(&mut self.buffer));
self.buffer_len_left = 0;
text = rest;
}
self.rope_has_trailing_newline = self.buffer.has_trailing_newline();
self
}
#[inline]
fn buffer_left_chunk(&self) -> &str {
unsafe {
core::str::from_utf8_unchecked(
&self.buffer.bytes[..self.buffer_len_left],
)
}
}
#[inline]
pub fn build(mut self) -> Rope {
if self.buffer_len_left > 0 {
self.buffer.left_summary =
ChunkSummary::from(self.buffer_left_chunk());
self.rope_has_trailing_newline =
self.buffer.has_trailing_newline();
self.tree_builder.append(self.buffer);
}
Rope {
tree: self.tree_builder.build(),
has_trailing_newline: self.rope_has_trailing_newline,
}
}
#[inline]
pub fn new() -> Self {
Self::default()
}
}