TGViewer
Блог* Блог* @dereference_pointer_there · 1.99K subscribers
Post #10639 879
Продолжим:
        ...
let len = s.len();
let ptr = {
let alloc_len = len
.checked_add(USIZE_SIZE)
.expect("length overflow");
let layout = std::alloc::Layout::array::<u8>(alloc_len)
.unwrap()
.align_to(USIZE_ALIGN)
.expect("invalid layout");
self.mem.alloc_layout(layout)
};
let s = unsafe {
ptr.cast::<usize>().write(len);
ptr.byte_add(USIZE_SIZE)
.as_ptr()
.copy_from_nonoverlapping(s.as_ptr(), len);
InternedStr::from_ptr(ptr)
};
...


Bump возвращает указатель на только что выделенную память и потому память под ним никак не может пересекаться с переданной аргументом строкой, поэтому мы можем безопасно воспользоваться copy_from_nonoverlapping

Теперь осталось лишь сохранить вновь созданную строку и вернуть её:

        ...
strs.insert(unsafe { s.reborrow_unchecked() });
s
}


reborrow_unchecked тут — это метод для принудительной смены времени жизни InternedStr:

impl InternedStr<'_> {
unsafe fn reborrow_unchecked<'b>(self) -> InternedStr<'b> {
InternedStr {
ptr: self.ptr,
_lt: PhantomData,
}
}
}


Как и обещано, безопасность обеспечена API: метод для выделения строки заимствует Interner, поэтому использовать возвращённые строки после дропа Interner нельзя.

Как же решается переиспользование памяти? Через делегацию Bump, главным образом:

impl Interner {
pub fn clear(&mut self) {
self.strs.get_mut().clear();
self.mem.reset();
}
}


Из-за уникального заимствования вызов этого метода инвалидирует все ранее выделенные строки, поэтому обратиться к интернированной строке после очищения пула строк нельзя.

И ещё пара моментов. Использование strs.get(s), где s имеет тип &str, а в множестве хранятся значения другого типа InternedStr, возможно только при условии, что InternedStr "похож" на str — или, иными словами, реализовывает Borrow<str>. Реализация делается элементарно через делегацию методу as_str. Также InternedStr, очевидно, нужно уметь хэшировать, и хэш должен считаться так же, как и для соответствующей строки. По этой причине #[derive(Hash)] не подойдёт и нужно писать его реализацию руками:

impl Hash for InternedStr<'_> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_str().hash(state)
}
}
  • ❤ 2
  • 👍 1
  • 🤔 1
More from @dereference_pointer_there
  1. Oct 10, 2026#prog #article HTTP is not simple От Daniel Stenberg, автора curl
  2. Oct 10, 2026#article RISC-V: They Should Have Known Better Несколько эмоциональная статья о недостатка…
  3. Oct 9, 2026#prog #rust #meme Было в r/rustjerk, но сначала выложили в r/ClaudeCode
  4. Oct 9, 2026Welp
  5. Oct 9, 2026#prog #article Оттуда: The case against JPEG XL
  6. Oct 9, 2026#prog #article Shipping JPEG XL in Chrome Но в треде на r/rust пишут, что есть сомнения в…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →