From a75def66cd533e9f58722e81352e376fce8bf370 Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Tue, 11 Jul 2023 11:11:59 -0700 Subject: [PATCH] Define the shape of BytesMut with stubbed methods This is the primary mutator for `bytes` fields, which proxy `[u8]`. PiperOrigin-RevId: 547242972 --- rust/BUILD | 2 + rust/protobuf.rs | 4 +- rust/shared.rs | 2 + rust/string.rs | 286 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 rust/string.rs diff --git a/rust/BUILD b/rust/BUILD index 7640ac98f3..303bf6a0c8 100644 --- a/rust/BUILD +++ b/rust/BUILD @@ -53,6 +53,7 @@ rust_library( "optional.rs", "proxied.rs", "shared.rs", + "string.rs", "upb.rs", ], crate_root = "shared.rs", @@ -89,6 +90,7 @@ rust_library( "optional.rs", "proxied.rs", "shared.rs", + "string.rs", ], crate_root = "shared.rs", rustc_flags = ["--cfg=cpp_kernel"], diff --git a/rust/protobuf.rs b/rust/protobuf.rs index b668159915..ac4c4e0b2c 100644 --- a/rust/protobuf.rs +++ b/rust/protobuf.rs @@ -41,4 +41,6 @@ use protobuf_cpp as kernel; #[cfg(upb_kernel)] use protobuf_upb as kernel; -pub use kernel::{Mut, MutProxy, ParseError, Proxied, ProxiedWithPresence, View, ViewProxy}; +pub use kernel::{ + BytesMut, Mut, MutProxy, ParseError, Proxied, ProxiedWithPresence, View, ViewProxy, +}; diff --git a/rust/shared.rs b/rust/shared.rs index ae4d566266..f3878945db 100644 --- a/rust/shared.rs +++ b/rust/shared.rs @@ -45,9 +45,11 @@ pub mod __runtime; mod optional; mod proxied; +mod string; pub use optional::{AbsentField, FieldEntry, Optional, PresentField}; pub use proxied::{Mut, MutProxy, Proxied, ProxiedWithPresence, SettableValue, View, ViewProxy}; +pub use string::BytesMut; /// Everything in `__internal` is allowed to change without it being considered /// a breaking change for the protobuf library. Nothing in here should be diff --git a/rust/string.rs b/rust/string.rs new file mode 100644 index 0000000000..7f287a0c5e --- /dev/null +++ b/rust/string.rs @@ -0,0 +1,286 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +//! Items specific to `bytes` and `string` fields. +#![allow(dead_code)] +#![allow(unused)] + +use crate::__internal::Private; +use crate::{Mut, MutProxy, Proxied, ProxiedWithPresence, SettableValue, View, ViewProxy}; +use std::borrow::Cow; +use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use std::convert::{AsMut, AsRef}; +use std::hash::{Hash, Hasher}; +use std::ops::{Deref, DerefMut}; + +/// This type will be replaced by something else in a future revision. +// TODO(b/285309330): remove this and any `impl`s using it. +pub type Todo<'msg> = (std::convert::Infallible, std::marker::PhantomData<&'msg mut ()>); + +/// A mutator for `bytes` fields - this type is `protobuf::Mut<'msg, [u8]>`. +/// +/// This type implements `DerefMut`, so many operations are +/// provided through that, including indexing and slicing. +/// +/// Conceptually, this type is a `&'msg mut Vec`, though the actual +/// implementation is dependent on runtime. Unlike `Vec`, this type has no +/// in-place concatenation functions like `extend_from_slice`. `BytesMut` is not +/// intended to be grown and reallocated like a `Vec`. It's recommended to +/// instead build a `Vec` or `String` and pass that directly to `set`, which +/// will reuse the allocation if supported by the runtime. +#[derive(Debug)] +pub struct BytesMut<'msg>(Todo<'msg>); + +impl<'msg> BytesMut<'msg> { + /// Sets the byte string to the given `val`, cloning any borrowed data. + /// + /// This method accepts both owned and borrowed byte strings; if the runtime + /// supports it, an owned value will not reallocate when setting the + /// string. + pub fn set(&mut self, val: impl SettableValue<[u8]>) { + val.set_on(Private, MutProxy::as_mut(self)) + } + + /// Truncates the byte string without reallocating. + /// + /// Has no effect if `new_len` is larger than the current `len`. + pub fn truncate(&mut self, new_len: usize) { + todo!("b/285309330") + } + + /// Clears the byte string to the empty string. + /// + /// # Compared with `FieldEntry::clear` + /// + /// Note that this is different than marking an `optional bytes` field as + /// absent; if these `bytes` are in an `optional`, `FieldEntry::is_set` + /// will still return `true` after this method is invoked. + /// + /// This also means that if the field has a non-empty default, + /// `BytesMut::clear` results in the accessor returning an empty string + /// while `FieldEntry::clear` results in the non-empty default. + /// + /// However, for a proto3 `bytes` that has implicit presence, there is no + /// distinction between these states: unset `bytes` is the same as empty + /// `bytes` and the default is always the empty string. + /// + /// In the C++ API, this is the difference between `msg.clear_bytes_field()` + /// and `msg.mutable_bytes_field()->clear()`. + /// + /// Having the same name and signature as `FieldEntry::clear` makes code + /// that calls `field_mut().clear()` easier to migrate from implicit + /// to explicit presence. + pub fn clear(&mut self) { + self.truncate(0); + } +} + +impl Deref for BytesMut<'_> { + type Target = [u8]; + fn deref(&self) -> &[u8] { + self.as_ref() + } +} + +impl DerefMut for BytesMut<'_> { + fn deref_mut(&mut self) -> &mut [u8] { + AsMut::as_mut(self) + } +} + +impl AsRef<[u8]> for BytesMut<'_> { + fn as_ref(&self) -> &[u8] { + todo!("b/285309330") + } +} + +impl AsMut<[u8]> for BytesMut<'_> { + fn as_mut(&mut self) -> &mut [u8] { + todo!("b/285309330") + } +} + +impl Proxied for [u8] { + type View<'msg> = &'msg [u8]; + type Mut<'msg> = BytesMut<'msg>; +} + +impl<'msg> ViewProxy<'msg> for Todo<'msg> { + type Proxied = [u8]; + fn as_view(&self) -> &[u8] { + unreachable!() + } + fn into_view<'shorter>(self) -> &'shorter [u8] + where + 'msg: 'shorter, + { + unreachable!() + } +} +impl<'msg> MutProxy<'msg> for Todo<'msg> { + fn as_mut(&mut self) -> BytesMut<'msg> { + unreachable!() + } + fn into_mut<'shorter>(self) -> BytesMut<'shorter> + where + 'msg: 'shorter, + { + unreachable!() + } +} + +impl ProxiedWithPresence for [u8] { + type PresentMutData<'msg> = Todo<'msg>; + type AbsentMutData<'msg> = Todo<'msg>; + + fn clear_present_field<'a>( + present_mutator: Self::PresentMutData<'a>, + ) -> Self::AbsentMutData<'a> { + todo!("b/285309330") + } + + fn set_absent_to_default<'a>( + absent_mutator: Self::AbsentMutData<'a>, + ) -> Self::PresentMutData<'a> { + todo!("b/285309330") + } +} + +impl<'msg> ViewProxy<'msg> for &'msg [u8] { + type Proxied = [u8]; + + fn as_view(&self) -> &[u8] { + self + } + + fn into_view<'shorter>(self) -> &'shorter [u8] + where + 'msg: 'shorter, + { + self + } +} + +impl<'msg> ViewProxy<'msg> for BytesMut<'msg> { + type Proxied = [u8]; + + fn as_view(&self) -> &[u8] { + self.as_ref() + } + + fn into_view<'shorter>(self) -> &'shorter [u8] + where + 'msg: 'shorter, + { + todo!("b/285309330") + } +} + +impl<'msg> MutProxy<'msg> for BytesMut<'msg> { + fn as_mut(&mut self) -> BytesMut<'_> { + todo!("b/285309330") + } + + fn into_mut<'shorter>(self) -> BytesMut<'shorter> + where + 'msg: 'shorter, + { + todo!("b/285309330") + } +} + +impl SettableValue<[u8]> for &'_ [u8] { + fn set_on(self, _private: Private, mutator: BytesMut<'_>) { + todo!("b/285309330") + } +} + +impl SettableValue<[u8]> for &'_ [u8; N] { + fn set_on(self, _private: Private, mutator: BytesMut<'_>) { + self[..].set_on(Private, mutator) + } +} + +impl SettableValue<[u8]> for Vec { + fn set_on(self, _private: Private, mutator: BytesMut<'_>) { + todo!("b/285309330") + } +} + +impl SettableValue<[u8]> for Cow<'_, [u8]> { + fn set_on(self, _private: Private, mutator: BytesMut<'_>) { + match self { + Cow::Borrowed(s) => s.set_on(Private, mutator), + Cow::Owned(v) => v.set_on(Private, mutator), + } + } +} + +impl Hash for BytesMut<'_> { + fn hash(&self, state: &mut H) { + self.deref().hash(state) + } +} + +/// Implements `PartialCmp` and `PartialEq` for the `lhs` against the `rhs` +/// using `AsRef<[u8]>`. +macro_rules! impl_bytes_partial_cmp { + ($(<($($generics:tt)*)> $lhs:ty => $rhs:ty),+ $(,)?) => { + $( + impl<$($generics)*> PartialEq<$rhs> for $lhs { + fn eq(&self, other: &$rhs) -> bool { + AsRef::<[u8]>::as_ref(self) == AsRef::<[u8]>::as_ref(other) + } + } + impl<$($generics)*> PartialOrd<$rhs> for $lhs { + fn partial_cmp(&self, other: &$rhs) -> Option { + AsRef::<[u8]>::as_ref(self).partial_cmp(AsRef::<[u8]>::as_ref(other)) + } + } + )* + }; +} + +impl_bytes_partial_cmp!( + <('a, 'b)> BytesMut<'a> => BytesMut<'b>, + <('a)> BytesMut<'a> => [u8], + <('a, const N: usize)> BytesMut<'a> => [u8; N], + <('a)> BytesMut<'a> => str, + <('a)> [u8] => BytesMut<'a>, + <('a, const N: usize)> [u8; N] => BytesMut<'a>, + <('a)> str => BytesMut<'a>, +); + +impl Eq for BytesMut<'_> {} +impl<'msg> Ord for BytesMut<'msg> { + fn cmp(&self, other: &BytesMut<'msg>) -> Ordering { + self.deref().cmp(other.deref()) + } +}