diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a12a7a..db5aca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + ## [Unreleased] ### Added +- Adds method `into_buf` for `Box` and `impl From for Box`. - Adds unsafe associated methods `Pointer::new_unchecked` and `PointerBuf::new_unchecked` for external zero-cost construction. diff --git a/src/pointer.rs b/src/pointer.rs index 4f136bb..6a073d7 100644 --- a/src/pointer.rs +++ b/src/pointer.rs @@ -1,6 +1,7 @@ use crate::{token::InvalidEncodingError, Components, Token, Tokens}; use alloc::{ borrow::ToOwned, + boxed::Box, fmt, string::{String, ToString}, vec::Vec, @@ -558,6 +559,14 @@ impl Pointer { pub fn is_empty(&self) -> bool { self.0.is_empty() } + + /// Converts a `Box` into a `PointerBuf` without copying or allocating. + pub fn into_buf(self: Box) -> PointerBuf { + let inner = Box::into_raw(self); + // SAFETY: we ensure the layout of `Pointer` is the same as `str` + let inner = unsafe { Box::::from_raw(inner as *mut str) }; + PointerBuf(inner.into_string()) + } } #[cfg(feature = "serde")] @@ -1002,6 +1011,14 @@ impl Deref for PointerBuf { } } +impl From for Box { + fn from(value: PointerBuf) -> Self { + let s = value.0.into_boxed_str(); + // SAFETY: we ensure that the layout of `str` is the same as `Pointer` + unsafe { Box::from_raw(Box::into_raw(s) as *mut Pointer) } + } +} + #[cfg(feature = "serde")] impl<'de> serde::Deserialize<'de> for PointerBuf { fn deserialize(deserializer: D) -> Result @@ -2212,4 +2229,12 @@ mod tests { let borrowed: &Pointer = ptr.borrow(); assert_eq!(borrowed, "/foo/bar"); } + + #[test] + fn from_box_to_buf() { + let original = PointerBuf::parse("/foo/bar/0").unwrap(); + let boxed: Box = original.clone().into(); + let unboxed = boxed.into_buf(); + assert_eq!(original, unboxed); + } }