diff --git a/src/pg/protocol/parameter_status.rs b/src/pg/protocol/parameter_status.rs index c35c1fc1..a033316d 100644 --- a/src/pg/protocol/parameter_status.rs +++ b/src/pg/protocol/parameter_status.rs @@ -1,42 +1,52 @@ -use super::Decode; -use bytes::Bytes; +use super::decode::{Decode, get_str}; +use std::pin::Pin; +use std::ptr::NonNull; use std::{io, str}; // FIXME: Use &str functions for a custom Debug #[derive(Debug)] pub struct ParameterStatus { - name: Vec, - value: Vec, + #[used] + storage: Pin>, + name: NonNull, + value: NonNull, } +// SAFE: Raw pointers point to pinned memory inside the struct +unsafe impl Send for ParameterStatus {} +unsafe impl Sync for ParameterStatus {} + impl ParameterStatus { #[inline] pub fn name(&self) -> &str { - unsafe { str::from_utf8_unchecked(&self.name) } + // SAFE: Memory is pinned + unsafe { self.name.as_ref() } } #[inline] pub fn value(&self) -> &str { - unsafe { str::from_utf8_unchecked(&self.value) } + // SAFE: Memory is pinned + unsafe { self.value.as_ref() } } } impl Decode for ParameterStatus { fn decode(src: &[u8]) -> io::Result { - let name_end = memchr::memchr(0, &src).unwrap(); - let value_end = memchr::memchr(0, &src[(name_end + 1)..]).unwrap(); + let storage = Pin::new(Vec::from(src)); - let name = src[..name_end].into(); - let value = src[(name_end + 1)..(name_end + 1 + value_end)].into(); + let name = get_str(&storage).unwrap(); + let value = get_str(&storage[name.len() + 1..]).unwrap(); - Ok(Self { name, value }) + let name = NonNull::from(name); + let value = NonNull::from(value); + + Ok(Self { storage, name, value }) } } #[cfg(test)] mod tests { use super::{Decode, ParameterStatus}; - use bytes::Bytes; use std::io; const PARAM_STATUS: &[u8] = b"session_authorization\0postgres\0";