diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /library/proc_macro/src/bridge/rpc.rs | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/proc_macro/src/bridge/rpc.rs')
-rw-r--r-- | library/proc_macro/src/bridge/rpc.rs | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs new file mode 100644 index 000000000..e9d7a46c0 --- /dev/null +++ b/library/proc_macro/src/bridge/rpc.rs @@ -0,0 +1,304 @@ +//! Serialization for client-server communication. + +use std::any::Any; +use std::char; +use std::io::Write; +use std::num::NonZeroU32; +use std::str; + +pub(super) type Writer = super::buffer::Buffer; + +pub(super) trait Encode<S>: Sized { + fn encode(self, w: &mut Writer, s: &mut S); +} + +pub(super) type Reader<'a> = &'a [u8]; + +pub(super) trait Decode<'a, 's, S>: Sized { + fn decode(r: &mut Reader<'a>, s: &'s S) -> Self; +} + +pub(super) trait DecodeMut<'a, 's, S>: Sized { + fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self; +} + +macro_rules! rpc_encode_decode { + (le $ty:ty) => { + impl<S> Encode<S> for $ty { + fn encode(self, w: &mut Writer, _: &mut S) { + w.extend_from_array(&self.to_le_bytes()); + } + } + + impl<S> DecodeMut<'_, '_, S> for $ty { + fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { + const N: usize = ::std::mem::size_of::<$ty>(); + + let mut bytes = [0; N]; + bytes.copy_from_slice(&r[..N]); + *r = &r[N..]; + + Self::from_le_bytes(bytes) + } + } + }; + (struct $name:ident $(<$($T:ident),+>)? { $($field:ident),* $(,)? }) => { + impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? { + fn encode(self, w: &mut Writer, s: &mut S) { + $(self.$field.encode(w, s);)* + } + } + + impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> + for $name $(<$($T),+>)? + { + fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + $name { + $($field: DecodeMut::decode(r, s)),* + } + } + } + }; + (enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => { + impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? { + fn encode(self, w: &mut Writer, s: &mut S) { + // HACK(eddyb): `Tag` enum duplicated between the + // two impls as there's no other place to stash it. + #[allow(non_upper_case_globals)] + mod tag { + #[repr(u8)] enum Tag { $($variant),* } + + $(pub const $variant: u8 = Tag::$variant as u8;)* + } + + match self { + $($name::$variant $(($field))* => { + tag::$variant.encode(w, s); + $($field.encode(w, s);)* + })* + } + } + } + + impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> + for $name $(<$($T),+>)? + { + fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + // HACK(eddyb): `Tag` enum duplicated between the + // two impls as there's no other place to stash it. + #[allow(non_upper_case_globals)] + mod tag { + #[repr(u8)] enum Tag { $($variant),* } + + $(pub const $variant: u8 = Tag::$variant as u8;)* + } + + match u8::decode(r, s) { + $(tag::$variant => { + $(let $field = DecodeMut::decode(r, s);)* + $name::$variant $(($field))* + })* + _ => unreachable!(), + } + } + } + } +} + +impl<S> Encode<S> for () { + fn encode(self, _: &mut Writer, _: &mut S) {} +} + +impl<S> DecodeMut<'_, '_, S> for () { + fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {} +} + +impl<S> Encode<S> for u8 { + fn encode(self, w: &mut Writer, _: &mut S) { + w.push(self); + } +} + +impl<S> DecodeMut<'_, '_, S> for u8 { + fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { + let x = r[0]; + *r = &r[1..]; + x + } +} + +rpc_encode_decode!(le u32); +rpc_encode_decode!(le usize); + +impl<S> Encode<S> for bool { + fn encode(self, w: &mut Writer, s: &mut S) { + (self as u8).encode(w, s); + } +} + +impl<S> DecodeMut<'_, '_, S> for bool { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + match u8::decode(r, s) { + 0 => false, + 1 => true, + _ => unreachable!(), + } + } +} + +impl<S> Encode<S> for char { + fn encode(self, w: &mut Writer, s: &mut S) { + (self as u32).encode(w, s); + } +} + +impl<S> DecodeMut<'_, '_, S> for char { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + char::from_u32(u32::decode(r, s)).unwrap() + } +} + +impl<S> Encode<S> for NonZeroU32 { + fn encode(self, w: &mut Writer, s: &mut S) { + self.get().encode(w, s); + } +} + +impl<S> DecodeMut<'_, '_, S> for NonZeroU32 { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + Self::new(u32::decode(r, s)).unwrap() + } +} + +impl<S, A: Encode<S>, B: Encode<S>> Encode<S> for (A, B) { + fn encode(self, w: &mut Writer, s: &mut S) { + self.0.encode(w, s); + self.1.encode(w, s); + } +} + +impl<'a, S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> + for (A, B) +{ + fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + (DecodeMut::decode(r, s), DecodeMut::decode(r, s)) + } +} + +impl<S> Encode<S> for &[u8] { + fn encode(self, w: &mut Writer, s: &mut S) { + self.len().encode(w, s); + w.write_all(self).unwrap(); + } +} + +impl<'a, S> DecodeMut<'a, '_, S> for &'a [u8] { + fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + let len = usize::decode(r, s); + let xs = &r[..len]; + *r = &r[len..]; + xs + } +} + +impl<S> Encode<S> for &str { + fn encode(self, w: &mut Writer, s: &mut S) { + self.as_bytes().encode(w, s); + } +} + +impl<'a, S> DecodeMut<'a, '_, S> for &'a str { + fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + str::from_utf8(<&[u8]>::decode(r, s)).unwrap() + } +} + +impl<S> Encode<S> for String { + fn encode(self, w: &mut Writer, s: &mut S) { + self[..].encode(w, s); + } +} + +impl<S> DecodeMut<'_, '_, S> for String { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + <&str>::decode(r, s).to_string() + } +} + +impl<S, T: Encode<S>> Encode<S> for Vec<T> { + fn encode(self, w: &mut Writer, s: &mut S) { + self.len().encode(w, s); + for x in self { + x.encode(w, s); + } + } +} + +impl<'a, S, T: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> for Vec<T> { + fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + let len = usize::decode(r, s); + let mut vec = Vec::with_capacity(len); + for _ in 0..len { + vec.push(T::decode(r, s)); + } + vec + } +} + +/// Simplified version of panic payloads, ignoring +/// types other than `&'static str` and `String`. +pub enum PanicMessage { + StaticStr(&'static str), + String(String), + Unknown, +} + +impl From<Box<dyn Any + Send>> for PanicMessage { + fn from(payload: Box<dyn Any + Send + 'static>) -> Self { + if let Some(s) = payload.downcast_ref::<&'static str>() { + return PanicMessage::StaticStr(s); + } + if let Ok(s) = payload.downcast::<String>() { + return PanicMessage::String(*s); + } + PanicMessage::Unknown + } +} + +impl Into<Box<dyn Any + Send>> for PanicMessage { + fn into(self) -> Box<dyn Any + Send> { + match self { + PanicMessage::StaticStr(s) => Box::new(s), + PanicMessage::String(s) => Box::new(s), + PanicMessage::Unknown => { + struct UnknownPanicMessage; + Box::new(UnknownPanicMessage) + } + } + } +} + +impl PanicMessage { + pub fn as_str(&self) -> Option<&str> { + match self { + PanicMessage::StaticStr(s) => Some(s), + PanicMessage::String(s) => Some(s), + PanicMessage::Unknown => None, + } + } +} + +impl<S> Encode<S> for PanicMessage { + fn encode(self, w: &mut Writer, s: &mut S) { + self.as_str().encode(w, s); + } +} + +impl<S> DecodeMut<'_, '_, S> for PanicMessage { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + match Option::<String>::decode(r, s) { + Some(s) => PanicMessage::String(s), + None => PanicMessage::Unknown, + } + } +} |