162 lines
3.8 KiB
Rust
162 lines
3.8 KiB
Rust
use crate::prolog::machine::machine_indices::*;
|
|
use crate::prolog::machine::raw_block::*;
|
|
|
|
use std::mem;
|
|
use std::ptr;
|
|
use std::slice;
|
|
use std::str;
|
|
|
|
pub(crate) struct PartialStringTraits {}
|
|
|
|
impl RawBlockTraits for PartialStringTraits {
|
|
#[inline]
|
|
fn init_size() -> usize {
|
|
0
|
|
}
|
|
|
|
#[inline]
|
|
fn align() -> usize {
|
|
mem::align_of::<char>()
|
|
}
|
|
}
|
|
|
|
pub struct PartialString {
|
|
pub(super) buf: RawBlock<PartialStringTraits>,
|
|
pub(super) tail: Addr,
|
|
}
|
|
|
|
impl Clone for PartialString {
|
|
#[inline]
|
|
fn clone(&self) -> Self {
|
|
self.clone_from_offset(0)
|
|
}
|
|
}
|
|
|
|
impl PartialEq for PartialString {
|
|
#[inline]
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self as *const _ == other as *const _
|
|
}
|
|
}
|
|
|
|
fn scan_for_terminator(src: &str) -> usize {
|
|
let mut terminator_idx = 0;
|
|
|
|
for c in src.chars() {
|
|
if c == '\u{0}' {
|
|
break;
|
|
}
|
|
|
|
terminator_idx += c.len_utf8();
|
|
}
|
|
|
|
terminator_idx
|
|
}
|
|
|
|
impl PartialString {
|
|
pub(super)
|
|
fn new(src: &str, h: usize) -> Option<(Self, &str)> {
|
|
let pstr = PartialString {
|
|
buf: RawBlock::with_capacity(src.len() + '\u{0}'.len_utf8()),
|
|
tail: Addr::PStrTail(h, 0),
|
|
};
|
|
|
|
unsafe {
|
|
pstr.append_chars(src)
|
|
}
|
|
}
|
|
|
|
unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
|
|
let terminator_idx = scan_for_terminator(src);
|
|
|
|
if terminator_idx == 0 {
|
|
return None;
|
|
}
|
|
|
|
let new_top = self.buf.new_block(terminator_idx + '\u{0}'.len_utf8());
|
|
|
|
ptr::copy(
|
|
src.as_ptr(),
|
|
self.buf.top as *mut _,
|
|
terminator_idx,
|
|
);
|
|
|
|
self.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
|
|
self.write_terminator_at(terminator_idx);
|
|
|
|
Some(if terminator_idx != src.len() {
|
|
(self, &src[terminator_idx + '\u{0}'.len_utf8() ..])
|
|
} else {
|
|
(self, "")
|
|
})
|
|
}
|
|
|
|
/* Ordinarily cloning of heap cell values is done in copy_term,
|
|
* so we rely on it to set the tail correctly. here it's set to PStrTail(0, 0),
|
|
* because we don't know its heap location. */
|
|
pub(super)
|
|
fn clone_from_offset(&self, n: usize) -> Self {
|
|
let mut pstr = PartialString {
|
|
buf: RawBlock::with_capacity(self.len() + '\u{0}'.len_utf8()),
|
|
tail: Addr::PStrTail(0, 0),
|
|
};
|
|
|
|
unsafe {
|
|
let len = if self.len() > n { self.len() - n } else { 0 };
|
|
let new_top = pstr.buf.new_block(len + '\u{0}'.len_utf8());
|
|
|
|
if len > 0 {
|
|
ptr::copy(
|
|
(self.buf.base as usize + n) as *mut u8,
|
|
pstr.buf.base as *mut _,
|
|
len,
|
|
);
|
|
}
|
|
|
|
pstr.write_terminator_at(len);
|
|
pstr.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
|
|
}
|
|
|
|
pstr
|
|
}
|
|
|
|
#[inline]
|
|
pub(super)
|
|
fn write_terminator_at(&mut self, index: usize) {
|
|
unsafe {
|
|
ptr::write(
|
|
(self.buf.base as usize + index) as *mut u8,
|
|
0u8,
|
|
);
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate)
|
|
fn block_as_str(&self) -> &str {
|
|
unsafe {
|
|
let slice = slice::from_raw_parts(self.buf.base, self.len());
|
|
str::from_utf8(slice).unwrap()
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate)
|
|
fn tail_addr(&self) -> &Addr {
|
|
&self.tail
|
|
}
|
|
|
|
#[inline]
|
|
pub fn len(&self) -> usize {
|
|
self.buf.top as usize - self.buf.base as usize
|
|
}
|
|
|
|
#[inline]
|
|
pub fn truncate(&mut self, len: usize) {
|
|
if (len + self.buf.base as usize) < self.buf.top as usize {
|
|
self.buf.top = (len + self.buf.base as usize) as *const _;
|
|
self.write_terminator_at(len);
|
|
}
|
|
}
|
|
}
|