From bf1c3f6a14d41785416e89eaa909a674021e7727 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 26 Jan 2026 11:02:50 +0000 Subject: [PATCH 01/16] move `Types` from `with_api!` to `Server` --- .../rustc_expand/src/proc_macro_server.rs | 4 +- library/proc_macro/src/bridge/client.rs | 13 +- library/proc_macro/src/bridge/mod.rs | 127 ++++++++---------- library/proc_macro/src/bridge/server.rs | 59 ++++---- .../crates/proc-macro-srv/src/dylib.rs | 2 +- .../src/server_impl/rust_analyzer_span.rs | 4 +- .../src/server_impl/token_id.rs | 4 +- 7 files changed, 84 insertions(+), 129 deletions(-) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index a51aa90355bcd..12490880ab0eb 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -458,13 +458,11 @@ impl<'a, 'b> Rustc<'a, 'b> { } } -impl server::Types for Rustc<'_, '_> { +impl server::Server for Rustc<'_, '_> { type TokenStream = TokenStream; type Span = Span; type Symbol = Symbol; -} -impl server::Server for Rustc<'_, '_> { fn globals(&mut self) -> ExpnGlobals { ExpnGlobals { def_site: self.def_site, diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 0d87a727ae40b..381c8502c8538 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -67,12 +67,6 @@ impl Decode<'_, '_, S> for Span { } } -// FIXME(eddyb) generate these impls by pattern-matching on the -// names of methods - also could use the presence of `fn drop` -// to distinguish between 'owned and 'interned, above. -// Alternatively, special "modes" could be listed of types in with_api -// instead of pattern matching on methods, here and in server decl. - impl Clone for TokenStream { fn clone(&self) -> Self { Methods::ts_clone(self) @@ -104,10 +98,7 @@ pub(crate) use super::symbol::Symbol; macro_rules! define_client_side { ( - Methods { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }, - $($name:ident),* $(,)? + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* ) => { impl Methods { $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? { @@ -130,7 +121,7 @@ macro_rules! define_client_side { } } } -with_api!(self, self, define_client_side); +with_api!(self, define_client_side); struct Bridge<'a> { /// Reusable buffer (only `clear`-ed, never shrunk), primarily diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 6f7c8726f9253..f454861be4ed1 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -18,87 +18,71 @@ use crate::{Delimiter, Level, Spacing}; /// Higher-order macro describing the server RPC API, allowing automatic /// generation of type-safe Rust APIs, both client-side and server-side. /// -/// `with_api!(MySelf, my_self, my_macro)` expands to: +/// `with_api!(MySelf, my_macro)` expands to: /// ```rust,ignore (pseudo-code) /// my_macro! { -/// Methods { -/// // ... -/// fn lit_character(ch: char) -> MySelf::Literal; -/// // ... -/// fn lit_span(my_self: &MySelf::Literal) -> MySelf::Span; -/// fn lit_set_span(my_self: &mut MySelf::Literal, span: MySelf::Span); -/// }, -/// Literal, -/// Span, +/// fn lit_character(ch: char) -> MySelf::Literal; +/// fn lit_span(lit: &MySelf::Literal) -> MySelf::Span; +/// fn lit_set_span(lit: &mut MySelf::Literal, span: MySelf::Span); /// // ... /// } /// ``` /// -/// The first two arguments serve to customize the arguments names -/// and argument/return types, to enable several different usecases: -/// -/// If `my_self` is just `self`, then each `fn` signature can be used -/// as-is for a method. If it's anything else (`self_` in practice), -/// then the signatures don't have a special `self` argument, and -/// can, therefore, have a different one introduced. +/// The first argument serves to customize the argument/return types, +/// to enable several different usecases: /// /// If `MySelf` is just `Self`, then the types are only valid inside /// a trait or a trait impl, where the trait has associated types /// for each of the API types. If non-associated types are desired, /// a module name (`self` in practice) can be used instead of `Self`. macro_rules! with_api { - ($S:ident, $self:ident, $m:ident) => { + ($S:ident, $m:ident) => { $m! { - Methods { - fn injected_env_var(var: &str) -> Option; - fn track_env_var(var: &str, value: Option<&str>); - fn track_path(path: &str); - fn literal_from_str(s: &str) -> Result, ()>; - fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>); - - fn ts_drop(stream: $S::TokenStream); - fn ts_clone(stream: &$S::TokenStream) -> $S::TokenStream; - fn ts_is_empty(stream: &$S::TokenStream) -> bool; - fn ts_expand_expr(stream: &$S::TokenStream) -> Result<$S::TokenStream, ()>; - fn ts_from_str(src: &str) -> $S::TokenStream; - fn ts_to_string(stream: &$S::TokenStream) -> String; - fn ts_from_token_tree( - tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol>, - ) -> $S::TokenStream; - fn ts_concat_trees( - base: Option<$S::TokenStream>, - trees: Vec>, - ) -> $S::TokenStream; - fn ts_concat_streams( - base: Option<$S::TokenStream>, - streams: Vec<$S::TokenStream>, - ) -> $S::TokenStream; - fn ts_into_trees( - stream: $S::TokenStream - ) -> Vec>; - - fn span_debug(span: $S::Span) -> String; - fn span_parent(span: $S::Span) -> Option<$S::Span>; - fn span_source(span: $S::Span) -> $S::Span; - fn span_byte_range(span: $S::Span) -> Range; - fn span_start(span: $S::Span) -> $S::Span; - fn span_end(span: $S::Span) -> $S::Span; - fn span_line(span: $S::Span) -> usize; - fn span_column(span: $S::Span) -> usize; - fn span_file(span: $S::Span) -> String; - fn span_local_file(span: $S::Span) -> Option; - fn span_join(span: $S::Span, other: $S::Span) -> Option<$S::Span>; - fn span_subspan(span: $S::Span, start: Bound, end: Bound) -> Option<$S::Span>; - fn span_resolved_at(span: $S::Span, at: $S::Span) -> $S::Span; - fn span_source_text(span: $S::Span) -> Option; - fn span_save_span(span: $S::Span) -> usize; - fn span_recover_proc_macro_span(id: usize) -> $S::Span; - - fn symbol_normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>; - }, - TokenStream, - Span, - Symbol, + fn injected_env_var(var: &str) -> Option; + fn track_env_var(var: &str, value: Option<&str>); + fn track_path(path: &str); + fn literal_from_str(s: &str) -> Result, ()>; + fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>); + + fn ts_drop(stream: $S::TokenStream); + fn ts_clone(stream: &$S::TokenStream) -> $S::TokenStream; + fn ts_is_empty(stream: &$S::TokenStream) -> bool; + fn ts_expand_expr(stream: &$S::TokenStream) -> Result<$S::TokenStream, ()>; + fn ts_from_str(src: &str) -> $S::TokenStream; + fn ts_to_string(stream: &$S::TokenStream) -> String; + fn ts_from_token_tree( + tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol>, + ) -> $S::TokenStream; + fn ts_concat_trees( + base: Option<$S::TokenStream>, + trees: Vec>, + ) -> $S::TokenStream; + fn ts_concat_streams( + base: Option<$S::TokenStream>, + streams: Vec<$S::TokenStream>, + ) -> $S::TokenStream; + fn ts_into_trees( + stream: $S::TokenStream + ) -> Vec>; + + fn span_debug(span: $S::Span) -> String; + fn span_parent(span: $S::Span) -> Option<$S::Span>; + fn span_source(span: $S::Span) -> $S::Span; + fn span_byte_range(span: $S::Span) -> Range; + fn span_start(span: $S::Span) -> $S::Span; + fn span_end(span: $S::Span) -> $S::Span; + fn span_line(span: $S::Span) -> usize; + fn span_column(span: $S::Span) -> usize; + fn span_file(span: $S::Span) -> String; + fn span_local_file(span: $S::Span) -> Option; + fn span_join(span: $S::Span, other: $S::Span) -> Option<$S::Span>; + fn span_subspan(span: $S::Span, start: Bound, end: Bound) -> Option<$S::Span>; + fn span_resolved_at(span: $S::Span, at: $S::Span) -> $S::Span; + fn span_source_text(span: $S::Span) -> Option; + fn span_save_span(span: $S::Span) -> usize; + fn span_recover_proc_macro_span(id: usize) -> $S::Span; + + fn symbol_normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>; } }; } @@ -158,10 +142,7 @@ mod api_tags { macro_rules! declare_tags { ( - Methods { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }, - $($name:ident),* $(,)? + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* ) => { pub(super) enum Method { $($method),* @@ -169,7 +150,7 @@ mod api_tags { rpc_encode_decode!(enum Method { $($method),* }); } } - with_api!(self, self, declare_tags); + with_api!(self, declare_tags); } /// Helper to wrap associated types to allow trait impl dispatch. diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index b79de99844533..2fed45d3a0ab6 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -5,12 +5,12 @@ use std::marker::PhantomData; use super::*; -pub(super) struct HandleStore { +pub(super) struct HandleStore { token_stream: handle::OwnedStore>, span: handle::InternedStore>, } -impl HandleStore { +impl HandleStore { fn new(handle_counters: &'static client::HandleCounters) -> Self { HandleStore { token_stream: handle::OwnedStore::new(&handle_counters.token_stream), @@ -19,19 +19,19 @@ impl HandleStore { } } -impl Encode> for Marked { +impl Encode> for Marked { fn encode(self, w: &mut Writer, s: &mut HandleStore) { s.token_stream.alloc(self).encode(w, s); } } -impl Decode<'_, '_, HandleStore> for Marked { +impl Decode<'_, '_, HandleStore> for Marked { fn decode(r: &mut Reader<'_>, s: &mut HandleStore) -> Self { s.token_stream.take(handle::Handle::decode(r, &mut ())) } } -impl<'s, S: Types> Decode<'_, 's, HandleStore> +impl<'s, S: Server> Decode<'_, 's, HandleStore> for &'s Marked { fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore) -> Self { @@ -39,32 +39,32 @@ impl<'s, S: Types> Decode<'_, 's, HandleStore> } } -impl Encode> for Marked { +impl Encode> for Marked { fn encode(self, w: &mut Writer, s: &mut HandleStore) { s.span.alloc(self).encode(w, s); } } -impl Decode<'_, '_, HandleStore> for Marked { +impl Decode<'_, '_, HandleStore> for Marked { fn decode(r: &mut Reader<'_>, s: &mut HandleStore) -> Self { s.span.copy(handle::Handle::decode(r, &mut ())) } } -pub trait Types { - type TokenStream: 'static + Clone; - type Span: 'static + Copy + Eq + Hash; - type Symbol: 'static; +struct Dispatcher { + handle_store: HandleStore, + server: S, } -macro_rules! declare_server_traits { +macro_rules! define_server_dispatcher_impl { ( - Methods { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }, - $($name:ident),* $(,)? + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* ) => { - pub trait Server: Types { + pub trait Server { + type TokenStream: 'static + Clone; + type Span: 'static + Copy + Eq + Hash; + type Symbol: 'static; + fn globals(&mut self) -> ExpnGlobals; /// Intern a symbol received from RPC @@ -75,32 +75,21 @@ macro_rules! declare_server_traits { $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?;)* } - } -} -with_api!(Self, self_, declare_server_traits); -struct Dispatcher { - handle_store: HandleStore, - server: S, -} - -macro_rules! define_dispatcher_impl { - ( - Methods { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }, - $($name:ident),* $(,)? - ) => { // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. pub trait DispatcherTrait { // HACK(eddyb) these are here to allow `Self::$name` to work below. - $(type $name;)* + type TokenStream; + type Span; + type Symbol; fn dispatch(&mut self, buf: Buffer) -> Buffer; } impl DispatcherTrait for Dispatcher { - $(type $name = Marked;)* + type TokenStream = Marked; + type Span = Marked; + type Symbol = Marked; fn dispatch(&mut self, mut buf: Buffer) -> Buffer { let Dispatcher { handle_store, server } = self; @@ -136,7 +125,7 @@ macro_rules! define_dispatcher_impl { } } } -with_api!(Self, self_, define_dispatcher_impl); +with_api!(Self, define_server_dispatcher_impl); pub trait ExecutionStrategy { fn run_bridge_and_client( diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs index 8680e9180e3ab..9a65538675fe9 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs @@ -48,7 +48,7 @@ impl Expander { callback: Option>, ) -> Result, PanicMessage> where - as bridge::server::Types>::TokenStream: Default, + as bridge::server::Server>::TokenStream: Default, { self.inner .proc_macros diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index ec30630c10bbe..eacb100fbc9fa 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -30,13 +30,11 @@ pub struct RaSpanServer<'a> { pub callback: Option>, } -impl server::Types for RaSpanServer<'_> { +impl server::Server for RaSpanServer<'_> { type TokenStream = crate::token_stream::TokenStream; type Span = Span; type Symbol = Symbol; -} -impl server::Server for RaSpanServer<'_> { fn globals(&mut self) -> ExpnGlobals { ExpnGlobals { def_site: self.def_site, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index 3bf07290c8c05..70484c4dc28fe 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -36,13 +36,11 @@ pub struct SpanIdServer<'a> { pub callback: Option>, } -impl server::Types for SpanIdServer<'_> { +impl server::Server for SpanIdServer<'_> { type TokenStream = crate::token_stream::TokenStream; type Span = Span; type Symbol = Symbol; -} -impl server::Server for SpanIdServer<'_> { fn globals(&mut self) -> ExpnGlobals { ExpnGlobals { def_site: self.def_site, From 5fef797f6e8360b2457cb9a4133f59effb9c5d65 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 26 Jan 2026 14:00:39 +0000 Subject: [PATCH 02/16] inline `Writer` and `Reader` type aliases --- library/proc_macro/src/bridge/client.rs | 10 ++-- library/proc_macro/src/bridge/mod.rs | 5 +- library/proc_macro/src/bridge/rpc.rs | 64 ++++++++++++------------- library/proc_macro/src/bridge/server.rs | 10 ++-- library/proc_macro/src/bridge/symbol.rs | 8 ++-- 5 files changed, 48 insertions(+), 49 deletions(-) diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 381c8502c8538..83a3b21e35481 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -30,19 +30,19 @@ impl Drop for TokenStream { } impl Encode for TokenStream { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { mem::ManuallyDrop::new(self).handle.encode(w, s); } } impl Encode for &TokenStream { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { self.handle.encode(w, s); } } impl Decode<'_, '_, S> for TokenStream { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + fn decode(r: &mut &[u8], s: &mut S) -> Self { TokenStream { handle: handle::Handle::decode(r, s) } } } @@ -56,13 +56,13 @@ impl !Send for Span {} impl !Sync for Span {} impl Encode for Span { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { self.handle.encode(w, s); } } impl Decode<'_, '_, S> for Span { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + fn decode(r: &mut &[u8], s: &mut S) -> Self { Span { handle: handle::Handle::decode(r, s) } } } diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index f454861be4ed1..006aa5f973fc5 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -113,7 +113,7 @@ mod symbol; use buffer::Buffer; pub use rpc::PanicMessage; -use rpc::{Decode, Encode, Reader, Writer}; +use rpc::{Decode, Encode}; /// Configuration for establishing an active connection between a server and a /// client. The server creates the bridge config (`run_server` in `server.rs`), @@ -138,7 +138,8 @@ impl !Sync for BridgeConfig<'_> {} #[forbid(unsafe_code)] #[allow(non_camel_case_types)] mod api_tags { - use super::rpc::{Decode, Encode, Reader, Writer}; + use super::buffer::Buffer; + use super::rpc::{Decode, Encode}; macro_rules! declare_tags { ( diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs index ed67674a74ab7..254b176e19c59 100644 --- a/library/proc_macro/src/bridge/rpc.rs +++ b/library/proc_macro/src/bridge/rpc.rs @@ -4,28 +4,26 @@ use std::any::Any; use std::io::Write; use std::num::NonZero; -pub(super) type Writer = super::buffer::Buffer; +use super::buffer::Buffer; pub(super) trait Encode: Sized { - fn encode(self, w: &mut Writer, s: &mut S); + fn encode(self, w: &mut Buffer, 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 mut S) -> Self; + fn decode(r: &mut &'a [u8], s: &'s mut S) -> Self; } macro_rules! rpc_encode_decode { (le $ty:ty) => { impl Encode for $ty { - fn encode(self, w: &mut Writer, _: &mut S) { + fn encode(self, w: &mut Buffer, _: &mut S) { w.extend_from_array(&self.to_le_bytes()); } } impl Decode<'_, '_, S> for $ty { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { + fn decode(r: &mut &[u8], _: &mut S) -> Self { const N: usize = size_of::<$ty>(); let mut bytes = [0; N]; @@ -38,7 +36,7 @@ macro_rules! rpc_encode_decode { }; (struct $name:ident $(<$($T:ident),+>)? { $($field:ident),* $(,)? }) => { impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { $(self.$field.encode(w, s);)* } } @@ -46,7 +44,7 @@ macro_rules! rpc_encode_decode { impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S> for $name $(<$($T),+>)? { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + fn decode(r: &mut &'a [u8], s: &mut S) -> Self { $name { $($field: Decode::decode(r, s)),* } @@ -55,7 +53,7 @@ macro_rules! rpc_encode_decode { }; (enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => { impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { // HACK(eddyb): `Tag` enum duplicated between the // two impls as there's no other place to stash it. #[repr(u8)] enum Tag { $($variant),* } @@ -72,7 +70,7 @@ macro_rules! rpc_encode_decode { impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S> for $name $(<$($T),+>)? { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + fn decode(r: &mut &'a [u8], 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)] @@ -95,21 +93,21 @@ macro_rules! rpc_encode_decode { } impl Encode for () { - fn encode(self, _: &mut Writer, _: &mut S) {} + fn encode(self, _: &mut Buffer, _: &mut S) {} } impl Decode<'_, '_, S> for () { - fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {} + fn decode(_: &mut &[u8], _: &mut S) -> Self {} } impl Encode for u8 { - fn encode(self, w: &mut Writer, _: &mut S) { + fn encode(self, w: &mut Buffer, _: &mut S) { w.push(self); } } impl Decode<'_, '_, S> for u8 { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { + fn decode(r: &mut &[u8], _: &mut S) -> Self { let x = r[0]; *r = &r[1..]; x @@ -120,13 +118,13 @@ rpc_encode_decode!(le u32); rpc_encode_decode!(le usize); impl Encode for bool { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { (self as u8).encode(w, s); } } impl Decode<'_, '_, S> for bool { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + fn decode(r: &mut &[u8], s: &mut S) -> Self { match u8::decode(r, s) { 0 => false, 1 => true, @@ -136,31 +134,31 @@ impl Decode<'_, '_, S> for bool { } impl Encode for char { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { (self as u32).encode(w, s); } } impl Decode<'_, '_, S> for char { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + fn decode(r: &mut &[u8], s: &mut S) -> Self { char::from_u32(u32::decode(r, s)).unwrap() } } impl Encode for NonZero { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { self.get().encode(w, s); } } impl Decode<'_, '_, S> for NonZero { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + fn decode(r: &mut &[u8], s: &mut S) -> Self { Self::new(u32::decode(r, s)).unwrap() } } impl, B: Encode> Encode for (A, B) { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { self.0.encode(w, s); self.1.encode(w, s); } @@ -169,20 +167,20 @@ impl, B: Encode> Encode for (A, B) { impl<'a, S, A: for<'s> Decode<'a, 's, S>, B: for<'s> Decode<'a, 's, S>> Decode<'a, '_, S> for (A, B) { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + fn decode(r: &mut &'a [u8], s: &mut S) -> Self { (Decode::decode(r, s), Decode::decode(r, s)) } } impl Encode for &[u8] { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { self.len().encode(w, s); w.write_all(self).unwrap(); } } impl<'a, S> Decode<'a, '_, S> for &'a [u8] { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + fn decode(r: &mut &'a [u8], s: &mut S) -> Self { let len = usize::decode(r, s); let xs = &r[..len]; *r = &r[len..]; @@ -191,31 +189,31 @@ impl<'a, S> Decode<'a, '_, S> for &'a [u8] { } impl Encode for &str { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { self.as_bytes().encode(w, s); } } impl<'a, S> Decode<'a, '_, S> for &'a str { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + fn decode(r: &mut &'a [u8], s: &mut S) -> Self { str::from_utf8(<&[u8]>::decode(r, s)).unwrap() } } impl Encode for String { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { self[..].encode(w, s); } } impl Decode<'_, '_, S> for String { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + fn decode(r: &mut &[u8], s: &mut S) -> Self { <&str>::decode(r, s).to_string() } } impl> Encode for Vec { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { self.len().encode(w, s); for x in self { x.encode(w, s); @@ -224,7 +222,7 @@ impl> Encode for Vec { } impl<'a, S, T: for<'s> Decode<'a, 's, S>> Decode<'a, '_, S> for Vec { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { + fn decode(r: &mut &'a [u8], s: &mut S) -> Self { let len = usize::decode(r, s); let mut vec = Vec::with_capacity(len); for _ in 0..len { @@ -278,13 +276,13 @@ impl PanicMessage { } impl Encode for PanicMessage { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { self.as_str().encode(w, s); } } impl Decode<'_, '_, S> for PanicMessage { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + fn decode(r: &mut &[u8], s: &mut S) -> Self { match Option::::decode(r, s) { Some(s) => PanicMessage::String(s), None => PanicMessage::Unknown, diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 2fed45d3a0ab6..8f31d7aa9f55f 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -20,13 +20,13 @@ impl HandleStore { } impl Encode> for Marked { - fn encode(self, w: &mut Writer, s: &mut HandleStore) { + fn encode(self, w: &mut Buffer, s: &mut HandleStore) { s.token_stream.alloc(self).encode(w, s); } } impl Decode<'_, '_, HandleStore> for Marked { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore) -> Self { + fn decode(r: &mut &[u8], s: &mut HandleStore) -> Self { s.token_stream.take(handle::Handle::decode(r, &mut ())) } } @@ -34,19 +34,19 @@ impl Decode<'_, '_, HandleStore> for Marked Decode<'_, 's, HandleStore> for &'s Marked { - fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore) -> Self { + fn decode(r: &mut &[u8], s: &'s mut HandleStore) -> Self { &s.token_stream[handle::Handle::decode(r, &mut ())] } } impl Encode> for Marked { - fn encode(self, w: &mut Writer, s: &mut HandleStore) { + fn encode(self, w: &mut Buffer, s: &mut HandleStore) { s.span.alloc(self).encode(w, s); } } impl Decode<'_, '_, HandleStore> for Marked { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore) -> Self { + fn decode(r: &mut &[u8], s: &mut HandleStore) -> Self { s.span.copy(handle::Handle::decode(r, &mut ())) } } diff --git a/library/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs index edba142bad721..02b1d351ac161 100644 --- a/library/proc_macro/src/bridge/symbol.rs +++ b/library/proc_macro/src/bridge/symbol.rs @@ -94,25 +94,25 @@ impl fmt::Display for Symbol { } impl Encode for Symbol { - fn encode(self, w: &mut Writer, s: &mut S) { + fn encode(self, w: &mut Buffer, s: &mut S) { self.with(|sym| sym.encode(w, s)) } } impl Decode<'_, '_, server::HandleStore> for Marked { - fn decode(r: &mut Reader<'_>, s: &mut server::HandleStore) -> Self { + fn decode(r: &mut &[u8], s: &mut server::HandleStore) -> Self { Mark::mark(S::intern_symbol(<&str>::decode(r, s))) } } impl Encode> for Marked { - fn encode(self, w: &mut Writer, s: &mut server::HandleStore) { + fn encode(self, w: &mut Buffer, s: &mut server::HandleStore) { S::with_symbol_string(&self.unmark(), |sym| sym.encode(w, s)) } } impl Decode<'_, '_, S> for Symbol { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { + fn decode(r: &mut &[u8], s: &mut S) -> Self { Symbol::new(<&str>::decode(r, s)) } } From f8d05b6c855f64e11dc9bdec4db21bd4c3c6a969 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 26 Jan 2026 14:43:50 +0000 Subject: [PATCH 03/16] flatten the `api_tags` module --- library/proc_macro/src/bridge/client.rs | 2 +- library/proc_macro/src/bridge/mod.rs | 24 +++++++++--------------- library/proc_macro/src/bridge/rpc.rs | 6 ++++-- library/proc_macro/src/bridge/server.rs | 4 ++-- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 83a3b21e35481..8f4a79b389f62 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -106,7 +106,7 @@ macro_rules! define_client_side { let mut buf = bridge.cached_buffer.take(); buf.clear(); - api_tags::Method::$method.encode(&mut buf, &mut ()); + ApiTags::$method.encode(&mut buf, &mut ()); $($arg.encode(&mut buf, &mut ());)* buf = bridge.dispatch.call(buf); diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 006aa5f973fc5..cf6ffd86f4144 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -135,24 +135,18 @@ pub struct BridgeConfig<'a> { impl !Send for BridgeConfig<'_> {} impl !Sync for BridgeConfig<'_> {} -#[forbid(unsafe_code)] -#[allow(non_camel_case_types)] -mod api_tags { - use super::buffer::Buffer; - use super::rpc::{Decode, Encode}; - - macro_rules! declare_tags { - ( - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - ) => { - pub(super) enum Method { - $($method),* - } - rpc_encode_decode!(enum Method { $($method),* }); +macro_rules! declare_tags { + ( + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + ) => { + #[allow(non_camel_case_types)] + pub(super) enum ApiTags { + $($method),* } + rpc_encode_decode!(enum ApiTags { $($method),* }); } - with_api!(self, declare_tags); } +with_api!(self, declare_tags); /// Helper to wrap associated types to allow trait impl dispatch. /// That is, normally a pair of impls for `T::Foo` and `T::Bar` diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs index 254b176e19c59..5786c62d94643 100644 --- a/library/proc_macro/src/bridge/rpc.rs +++ b/library/proc_macro/src/bridge/rpc.rs @@ -56,7 +56,9 @@ macro_rules! rpc_encode_decode { fn encode(self, w: &mut Buffer, s: &mut S) { // HACK(eddyb): `Tag` enum duplicated between the // two impls as there's no other place to stash it. - #[repr(u8)] enum Tag { $($variant),* } + #[allow(non_camel_case_types)] + #[repr(u8)] + enum Tag { $($variant),* } match self { $($name::$variant $(($field))* => { @@ -73,7 +75,7 @@ macro_rules! rpc_encode_decode { fn decode(r: &mut &'a [u8], 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)] + #[allow(non_upper_case_globals, non_camel_case_types)] mod tag { #[repr(u8)] enum Tag { $($variant),* } diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 8f31d7aa9f55f..f477fa28798d2 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -95,8 +95,8 @@ macro_rules! define_server_dispatcher_impl { let Dispatcher { handle_store, server } = self; let mut reader = &buf[..]; - match api_tags::Method::decode(&mut reader, &mut ()) { - $(api_tags::Method::$method => { + match ApiTags::decode(&mut reader, &mut ()) { + $(ApiTags::$method => { let mut call_method = || { $(let $arg = <$arg_ty>::decode(&mut reader, handle_store).unmark();)* let r = server.$method($($arg),*); From d5328c545a0cad33053369ddbc0e5f27aa2924aa Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 26 Jan 2026 14:58:29 +0000 Subject: [PATCH 04/16] introduce `MarkedX` type aliases --- library/proc_macro/src/bridge/server.rs | 43 +++++++++++-------------- library/proc_macro/src/bridge/symbol.rs | 4 +-- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index f477fa28798d2..073ddb554994c 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -6,8 +6,8 @@ use std::marker::PhantomData; use super::*; pub(super) struct HandleStore { - token_stream: handle::OwnedStore>, - span: handle::InternedStore>, + token_stream: handle::OwnedStore>, + span: handle::InternedStore>, } impl HandleStore { @@ -19,33 +19,35 @@ impl HandleStore { } } -impl Encode> for Marked { +pub(super) type MarkedTokenStream = Marked<::TokenStream, client::TokenStream>; +pub(super) type MarkedSpan = Marked<::Span, client::Span>; +pub(super) type MarkedSymbol = Marked<::Symbol, client::Symbol>; + +impl Encode> for MarkedTokenStream { fn encode(self, w: &mut Buffer, s: &mut HandleStore) { s.token_stream.alloc(self).encode(w, s); } } -impl Decode<'_, '_, HandleStore> for Marked { +impl Decode<'_, '_, HandleStore> for MarkedTokenStream { fn decode(r: &mut &[u8], s: &mut HandleStore) -> Self { s.token_stream.take(handle::Handle::decode(r, &mut ())) } } -impl<'s, S: Server> Decode<'_, 's, HandleStore> - for &'s Marked -{ +impl<'s, S: Server> Decode<'_, 's, HandleStore> for &'s MarkedTokenStream { fn decode(r: &mut &[u8], s: &'s mut HandleStore) -> Self { &s.token_stream[handle::Handle::decode(r, &mut ())] } } -impl Encode> for Marked { +impl Encode> for MarkedSpan { fn encode(self, w: &mut Buffer, s: &mut HandleStore) { s.span.alloc(self).encode(w, s); } } -impl Decode<'_, '_, HandleStore> for Marked { +impl Decode<'_, '_, HandleStore> for MarkedSpan { fn decode(r: &mut &[u8], s: &mut HandleStore) -> Self { s.span.copy(handle::Handle::decode(r, &mut ())) } @@ -87,9 +89,9 @@ macro_rules! define_server_dispatcher_impl { } impl DispatcherTrait for Dispatcher { - type TokenStream = Marked; - type Span = Marked; - type Symbol = Marked; + type TokenStream = MarkedTokenStream; + type Span = MarkedSpan; + type Symbol = MarkedSymbol; fn dispatch(&mut self, mut buf: Buffer) -> Buffer { let Dispatcher { handle_store, server } = self; @@ -292,7 +294,7 @@ fn run_server< let globals = dispatcher.server.globals(); let mut buf = Buffer::new(); - (> as Mark>::mark(globals), input) + (> as Mark>::mark(globals), input) .encode(&mut buf, &mut dispatcher.handle_store); buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics); @@ -317,13 +319,11 @@ impl client::Client { strategy, handle_counters, server, - >::mark(input), + >::mark(input), run, force_show_panics, ) - .map(|s| { - >>::unmark(s).unwrap_or_default() - }) + .map(|s| >>::unmark(s).unwrap_or_default()) } } @@ -345,15 +345,10 @@ impl client::Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream strategy, handle_counters, server, - ( - >::mark(input), - >::mark(input2), - ), + (>::mark(input), >::mark(input2)), run, force_show_panics, ) - .map(|s| { - >>::unmark(s).unwrap_or_default() - }) + .map(|s| >>::unmark(s).unwrap_or_default()) } } diff --git a/library/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs index 02b1d351ac161..2a04f7d808bd5 100644 --- a/library/proc_macro/src/bridge/symbol.rs +++ b/library/proc_macro/src/bridge/symbol.rs @@ -99,13 +99,13 @@ impl Encode for Symbol { } } -impl Decode<'_, '_, server::HandleStore> for Marked { +impl Decode<'_, '_, server::HandleStore> for server::MarkedSymbol { fn decode(r: &mut &[u8], s: &mut server::HandleStore) -> Self { Mark::mark(S::intern_symbol(<&str>::decode(r, s))) } } -impl Encode> for Marked { +impl Encode> for server::MarkedSymbol { fn encode(self, w: &mut Buffer, s: &mut server::HandleStore) { S::with_symbol_string(&self.unmark(), |sym| sym.encode(w, s)) } From 356107e0b46182a080ab4876282cebbb97e33b1a Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 26 Jan 2026 14:27:18 +0000 Subject: [PATCH 05/16] remove some unneeded impls --- library/proc_macro/src/bridge/mod.rs | 17 +------------- library/proc_macro/src/bridge/rpc.rs | 35 +++++----------------------- 2 files changed, 7 insertions(+), 45 deletions(-) diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index cf6ffd86f4144..97e36a3d70c17 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -13,7 +13,7 @@ use std::ops::{Bound, Range}; use std::sync::Once; use std::{fmt, marker, mem, panic, thread}; -use crate::{Delimiter, Level, Spacing}; +use crate::{Delimiter, Level}; /// Higher-order macro describing the server RPC API, allowing automatic /// generation of type-safe Rust APIs, both client-side and server-side. @@ -187,12 +187,6 @@ impl<'a, T, M> Unmark for &'a Marked { &self.value } } -impl<'a, T, M> Unmark for &'a mut Marked { - type Unmarked = &'a mut T; - fn unmark(self) -> Self::Unmarked { - &mut self.value - } -} impl Mark for Vec { type Unmarked = Vec; @@ -230,8 +224,6 @@ macro_rules! mark_noop { mark_noop! { (), bool, - char, - &'_ [u8], &'_ str, String, u8, @@ -239,7 +231,6 @@ mark_noop! { Delimiter, LitKind, Level, - Spacing, } rpc_encode_decode!( @@ -258,12 +249,6 @@ rpc_encode_decode!( Help, } ); -rpc_encode_decode!( - enum Spacing { - Alone, - Joint, - } -); #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum LitKind { diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs index 5786c62d94643..63329c8c02601 100644 --- a/library/proc_macro/src/bridge/rpc.rs +++ b/library/proc_macro/src/bridge/rpc.rs @@ -135,18 +135,6 @@ impl Decode<'_, '_, S> for bool { } } -impl Encode for char { - fn encode(self, w: &mut Buffer, s: &mut S) { - (self as u32).encode(w, s); - } -} - -impl Decode<'_, '_, S> for char { - fn decode(r: &mut &[u8], s: &mut S) -> Self { - char::from_u32(u32::decode(r, s)).unwrap() - } -} - impl Encode for NonZero { fn encode(self, w: &mut Buffer, s: &mut S) { self.get().encode(w, s); @@ -174,31 +162,20 @@ impl<'a, S, A: for<'s> Decode<'a, 's, S>, B: for<'s> Decode<'a, 's, S>> Decode<' } } -impl Encode for &[u8] { +impl Encode for &str { fn encode(self, w: &mut Buffer, s: &mut S) { - self.len().encode(w, s); - w.write_all(self).unwrap(); + let bytes = self.as_bytes(); + bytes.len().encode(w, s); + w.write_all(bytes).unwrap(); } } -impl<'a, S> Decode<'a, '_, S> for &'a [u8] { +impl<'a, S> Decode<'a, '_, S> for &'a str { fn decode(r: &mut &'a [u8], s: &mut S) -> Self { let len = usize::decode(r, s); let xs = &r[..len]; *r = &r[len..]; - xs - } -} - -impl Encode for &str { - fn encode(self, w: &mut Buffer, s: &mut S) { - self.as_bytes().encode(w, s); - } -} - -impl<'a, S> Decode<'a, '_, S> for &'a str { - fn decode(r: &mut &'a [u8], s: &mut S) -> Self { - str::from_utf8(<&[u8]>::decode(r, s)).unwrap() + str::from_utf8(xs).unwrap() } } From 6e7a87c5c5a20d43e254986724e4d781556d8a53 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 26 Jan 2026 15:24:22 +0000 Subject: [PATCH 06/16] merge `Mark` and `Unmark` traits --- library/proc_macro/src/bridge/mod.rs | 31 ++++++---------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 97e36a3d70c17..244ab7d81b022 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -155,11 +155,6 @@ with_api!(self, declare_tags); trait Mark { type Unmarked; fn mark(unmarked: Self::Unmarked) -> Self; -} - -/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details). -trait Unmark { - type Unmarked; fn unmark(self) -> Self::Unmarked; } @@ -174,15 +169,15 @@ impl Mark for Marked { fn mark(unmarked: Self::Unmarked) -> Self { Marked { value: unmarked, _marker: marker::PhantomData } } -} -impl Unmark for Marked { - type Unmarked = T; fn unmark(self) -> Self::Unmarked { self.value } } -impl<'a, T, M> Unmark for &'a Marked { +impl<'a, T, M> Mark for &'a Marked { type Unmarked = &'a T; + fn mark(_: Self::Unmarked) -> Self { + unreachable!() + } fn unmark(self) -> Self::Unmarked { &self.value } @@ -194,9 +189,6 @@ impl Mark for Vec { // Should be a no-op due to std's in-place collect optimizations. unmarked.into_iter().map(T::mark).collect() } -} -impl Unmark for Vec { - type Unmarked = Vec; fn unmark(self) -> Self::Unmarked { // Should be a no-op due to std's in-place collect optimizations. self.into_iter().map(T::unmark).collect() @@ -211,9 +203,6 @@ macro_rules! mark_noop { fn mark(unmarked: Self::Unmarked) -> Self { unmarked } - } - impl Unmark for $ty { - type Unmarked = Self; fn unmark(self) -> Self::Unmarked { self } @@ -294,13 +283,9 @@ macro_rules! mark_compound { $($field: Mark::mark(unmarked.$field)),* } } - } - - impl<$($T: Unmark),+> Unmark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; fn unmark(self) -> Self::Unmarked { $name { - $($field: Unmark::unmark(self.$field)),* + $($field: Mark::unmark(self.$field)),* } } } @@ -315,14 +300,10 @@ macro_rules! mark_compound { })* } } - } - - impl<$($T: Unmark),+> Unmark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; fn unmark(self) -> Self::Unmarked { match self { $($name::$variant $(($field))? => { - $name::$variant $((Unmark::unmark($field)))? + $name::$variant $((Mark::unmark($field)))? })* } } From 814d902c503920334e3b992cb3d208b9742e24f3 Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 15 Jan 2026 14:27:10 +0100 Subject: [PATCH 07/16] std: move time implementations to `sys` (preparation) --- library/std/src/sys/mod.rs | 1 + library/std/src/sys/time/mod.rs | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 library/std/src/sys/time/mod.rs diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index c9035938cfdd3..5436c144d3330 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -26,6 +26,7 @@ pub mod stdio; pub mod sync; pub mod thread; pub mod thread_local; +pub mod time; // FIXME(117276): remove this, move feature implementations into individual // submodules. diff --git a/library/std/src/sys/time/mod.rs b/library/std/src/sys/time/mod.rs new file mode 100644 index 0000000000000..015871e6f1ec5 --- /dev/null +++ b/library/std/src/sys/time/mod.rs @@ -0,0 +1,4 @@ +cfg_select! { +} + +pub use imp::{Instant, SystemTime, UNIX_EPOCH}; From 29b16c0a55e14504ec24eddc0a3ace7074687ce4 Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 15 Jan 2026 14:38:41 +0100 Subject: [PATCH 08/16] std: move time implementations to `sys` (small platforms) Let's start with the easy ones: * Motor just reexports its platform library * The SGX code is just a trivial move * Trusty, WASM and ZKVM are unsupported, this is very trivial. And we can get rid of some `#[path = ...]`s, yay! --- library/std/src/sys/pal/motor/mod.rs | 1 - library/std/src/sys/pal/motor/time.rs | 1 - library/std/src/sys/pal/sgx/mod.rs | 1 - library/std/src/sys/pal/trusty/mod.rs | 2 -- library/std/src/sys/pal/unsupported/mod.rs | 1 - library/std/src/sys/pal/wasm/mod.rs | 2 -- library/std/src/sys/pal/xous/mod.rs | 1 - library/std/src/sys/pal/zkvm/mod.rs | 2 -- library/std/src/sys/time/mod.rs | 15 +++++++++++++++ .../std/src/sys/{pal/sgx/time.rs => time/sgx.rs} | 2 +- .../unsupported/time.rs => time/unsupported.rs} | 0 .../src/sys/{pal/xous/time.rs => time/xous.rs} | 0 12 files changed, 16 insertions(+), 12 deletions(-) delete mode 100644 library/std/src/sys/pal/motor/time.rs rename library/std/src/sys/{pal/sgx/time.rs => time/sgx.rs} (97%) rename library/std/src/sys/{pal/unsupported/time.rs => time/unsupported.rs} (100%) rename library/std/src/sys/{pal/xous/time.rs => time/xous.rs} (100%) diff --git a/library/std/src/sys/pal/motor/mod.rs b/library/std/src/sys/pal/motor/mod.rs index e5b99cea01d55..a520375a4bbff 100644 --- a/library/std/src/sys/pal/motor/mod.rs +++ b/library/std/src/sys/pal/motor/mod.rs @@ -1,7 +1,6 @@ #![allow(unsafe_op_in_unsafe_fn)] pub mod os; -pub mod time; pub use moto_rt::futex; diff --git a/library/std/src/sys/pal/motor/time.rs b/library/std/src/sys/pal/motor/time.rs deleted file mode 100644 index e917fd466c2e4..0000000000000 --- a/library/std/src/sys/pal/motor/time.rs +++ /dev/null @@ -1 +0,0 @@ -pub use moto_rt::time::{Instant, SystemTime, UNIX_EPOCH}; diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 7f1c81a0ff7bf..1de3ca4a5d79c 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -12,7 +12,6 @@ pub mod abi; mod libunwind_integration; pub mod os; pub mod thread_parking; -pub mod time; pub mod waitqueue; // SAFETY: must be called only once during runtime initialization. diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs index 76a3a75b10c1a..b785c2dbb7892 100644 --- a/library/std/src/sys/pal/trusty/mod.rs +++ b/library/std/src/sys/pal/trusty/mod.rs @@ -5,7 +5,5 @@ mod common; #[path = "../unsupported/os.rs"] pub mod os; -#[path = "../unsupported/time.rs"] -pub mod time; pub use common::*; diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index c33d2e5fb02a1..0f157819d5a66 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -1,7 +1,6 @@ #![deny(unsafe_op_in_unsafe_fn)] pub mod os; -pub mod time; mod common; pub use common::*; diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index 80429a9aae18d..5f56eddd6a819 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -18,8 +18,6 @@ #[path = "../unsupported/os.rs"] pub mod os; -#[path = "../unsupported/time.rs"] -pub mod time; #[cfg(target_feature = "atomics")] #[path = "atomics/futex.rs"] diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 19575220b22ee..87c99068929c3 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -1,7 +1,6 @@ #![forbid(unsafe_op_in_unsafe_fn)] pub mod os; -pub mod time; #[path = "../unsupported/common.rs"] mod common; diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index f09020820a031..1b18adb811d95 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -12,8 +12,6 @@ pub const WORD_SIZE: usize = size_of::(); pub mod abi; pub mod os; -#[path = "../unsupported/time.rs"] -pub mod time; use crate::io as std_io; diff --git a/library/std/src/sys/time/mod.rs b/library/std/src/sys/time/mod.rs index 015871e6f1ec5..81c568bf93202 100644 --- a/library/std/src/sys/time/mod.rs +++ b/library/std/src/sys/time/mod.rs @@ -1,4 +1,19 @@ cfg_select! { + target_os = "motor" => { + use moto_rt::time as imp; + } + all(target_vendor = "fortanix", target_env = "sgx") => { + mod sgx; + use sgx as imp; + } + target_os = "xous" => { + mod xous; + use xous as imp; + } + _ => { + mod unsupported; + use unsupported as imp; + } } pub use imp::{Instant, SystemTime, UNIX_EPOCH}; diff --git a/library/std/src/sys/pal/sgx/time.rs b/library/std/src/sys/time/sgx.rs similarity index 97% rename from library/std/src/sys/pal/sgx/time.rs rename to library/std/src/sys/time/sgx.rs index a9a448226619e..910e734c916e9 100644 --- a/library/std/src/sys/pal/sgx/time.rs +++ b/library/std/src/sys/time/sgx.rs @@ -1,4 +1,4 @@ -use super::abi::usercalls; +use crate::sys::pal::abi::usercalls; use crate::time::Duration; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] diff --git a/library/std/src/sys/pal/unsupported/time.rs b/library/std/src/sys/time/unsupported.rs similarity index 100% rename from library/std/src/sys/pal/unsupported/time.rs rename to library/std/src/sys/time/unsupported.rs diff --git a/library/std/src/sys/pal/xous/time.rs b/library/std/src/sys/time/xous.rs similarity index 100% rename from library/std/src/sys/pal/xous/time.rs rename to library/std/src/sys/time/xous.rs From 5978e194564d628afe2e54cc1068d0791a7e2e8d Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 15 Jan 2026 14:57:03 +0100 Subject: [PATCH 09/16] std: move time implementations to `sys` (VEX) Now that the `unsupported` module exists, we can use it for VEX. VEX actually supports `Instant` though, so the implementation-select needs to combine that with the `unsupported` module. --- library/std/src/sys/pal/vexos/mod.rs | 1 - library/std/src/sys/time/mod.rs | 10 ++++++++++ .../std/src/sys/{pal/vexos/time.rs => time/vexos.rs} | 5 ----- 3 files changed, 10 insertions(+), 6 deletions(-) rename library/std/src/sys/{pal/vexos/time.rs => time/vexos.rs} (83%) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 0abfc2fd79865..16aa3f088f04b 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -1,5 +1,4 @@ pub mod os; -pub mod time; #[expect(dead_code)] #[path = "../unsupported/common.rs"] diff --git a/library/std/src/sys/time/mod.rs b/library/std/src/sys/time/mod.rs index 81c568bf93202..0e3376e2f9106 100644 --- a/library/std/src/sys/time/mod.rs +++ b/library/std/src/sys/time/mod.rs @@ -6,6 +6,16 @@ cfg_select! { mod sgx; use sgx as imp; } + target_os = "vexos" => { + mod vexos; + #[expect(unused)] + mod unsupported; + + mod imp { + pub use super::vexos::Instant; + pub use super::unsupported::{SystemTime, UNIX_EPOCH}; + } + } target_os = "xous" => { mod xous; use xous as imp; diff --git a/library/std/src/sys/pal/vexos/time.rs b/library/std/src/sys/time/vexos.rs similarity index 83% rename from library/std/src/sys/pal/vexos/time.rs rename to library/std/src/sys/time/vexos.rs index f95d96cd27ac0..966c239699cec 100644 --- a/library/std/src/sys/pal/vexos/time.rs +++ b/library/std/src/sys/time/vexos.rs @@ -1,10 +1,5 @@ use crate::time::Duration; -#[expect(dead_code)] -#[path = "../unsupported/time.rs"] -mod unsupported_time; -pub use unsupported_time::{SystemTime, UNIX_EPOCH}; - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Instant(Duration); From bd754c7119a73bfc5e9e0d23071ebffc2ebce245 Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 15 Jan 2026 14:47:05 +0100 Subject: [PATCH 10/16] std: move time implementations to `sys` (Solid) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On SOLID, the conversion functions are also used to implement helpers for timeout conversion, so these stay in the PAL. The `Instant` (µITRON) and `SystemTime` (SOLID-specific) implementations are merged into one. While it was nice to have the µITRON parts in a separate module, there really isn't a need for this currently, as there is no other µITRON target. Let's not worry about this until such a target gets added... Note that I've extracted the `get_tim` call from `Instant` into a wrapper function in the PAL to avoid the need to make the inner `Instant` field public for use in the PAL. --- library/std/src/sys/pal/itron/time.rs | 47 +++++-------------- library/std/src/sys/pal/solid/mod.rs | 1 - library/std/src/sys/time/mod.rs | 4 ++ .../sys/{pal/solid/time.rs => time/solid.rs} | 35 ++++++++++++-- 4 files changed, 47 insertions(+), 40 deletions(-) rename library/std/src/sys/{pal/solid/time.rs => time/solid.rs} (65%) diff --git a/library/std/src/sys/pal/itron/time.rs b/library/std/src/sys/pal/itron/time.rs index 7976c27f4952b..ff3cffd2069e9 100644 --- a/library/std/src/sys/pal/itron/time.rs +++ b/library/std/src/sys/pal/itron/time.rs @@ -3,38 +3,16 @@ use super::error::expect_success; use crate::mem::MaybeUninit; use crate::time::Duration; -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(abi::SYSTIM); - -impl Instant { - pub fn now() -> Instant { - // Safety: The provided pointer is valid - unsafe { - let mut out = MaybeUninit::uninit(); - expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim"); - Instant(out.assume_init()) - } - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.0.checked_sub(other.0).map(|ticks| { - // `SYSTIM` is measured in microseconds - Duration::from_micros(ticks) - }) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - // `SYSTIM` is measured in microseconds - let ticks = other.as_micros(); - - Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?)) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - // `SYSTIM` is measured in microseconds - let ticks = other.as_micros(); +#[cfg(test)] +mod tests; - Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?)) +#[inline] +pub fn get_tim() -> abi::SYSTIM { + // Safety: The provided pointer is valid + unsafe { + let mut out = MaybeUninit::uninit(); + expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim"); + out.assume_init() } } @@ -98,7 +76,7 @@ pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) - // a problem in practice. (`u64::MAX` μs ≈ 584942 years) let ticks = dur.as_micros().min(abi::SYSTIM::MAX as u128) as abi::SYSTIM; - let start = Instant::now().0; + let start = get_tim(); let mut elapsed = 0; let mut er = abi::E_TMOUT; while elapsed <= ticks { @@ -106,11 +84,8 @@ pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) - if er != abi::E_TMOUT { break; } - elapsed = Instant::now().0.wrapping_sub(start); + elapsed = get_tim().wrapping_sub(start); } er } - -#[cfg(test)] -mod tests; diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 4eec12dacd7ca..1376af8304cf6 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -21,7 +21,6 @@ pub mod itron { pub(crate) mod error; pub mod os; pub use self::itron::thread_parking; -pub mod time; // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. diff --git a/library/std/src/sys/time/mod.rs b/library/std/src/sys/time/mod.rs index 0e3376e2f9106..e5b9a3a057f09 100644 --- a/library/std/src/sys/time/mod.rs +++ b/library/std/src/sys/time/mod.rs @@ -6,6 +6,10 @@ cfg_select! { mod sgx; use sgx as imp; } + target_os = "solid_asp3" => { + mod solid; + use solid as imp; + } target_os = "vexos" => { mod vexos; #[expect(unused)] diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/time/solid.rs similarity index 65% rename from library/std/src/sys/pal/solid/time.rs rename to library/std/src/sys/time/solid.rs index d5cf70f94c987..fa929c67241e3 100644 --- a/library/std/src/sys/pal/solid/time.rs +++ b/library/std/src/sys/time/solid.rs @@ -1,9 +1,38 @@ -use super::abi; -use super::error::expect_success; -pub use super::itron::time::Instant; use crate::mem::MaybeUninit; +use crate::sys::pal::error::expect_success; +use crate::sys::pal::{abi, itron}; use crate::time::Duration; +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(itron::abi::SYSTIM); + +impl Instant { + pub fn now() -> Instant { + Instant(itron::time::get_tim()) + } + + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.0.checked_sub(other.0).map(|ticks| { + // `SYSTIM` is measured in microseconds + Duration::from_micros(ticks) + }) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + // `SYSTIM` is measured in microseconds + let ticks = other.as_micros(); + + Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + // `SYSTIM` is measured in microseconds + let ticks = other.as_micros(); + + Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?)) + } +} + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct SystemTime(abi::time_t); From 963f6029ce51ce1b0654620b80d7f8cb089b3142 Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 15 Jan 2026 14:53:52 +0100 Subject: [PATCH 11/16] std: move time implementations to `sys` (UEFI) Next up: UEFI. Unfortunately the time conversion internals are also required by the filesystem code, so I've left them in the PAL. The `Instant` internals however are only used for the `Instant` implementation, so I've moved them to `sys` (for now). --- library/std/src/sys/fs/uefi.rs | 7 +- library/std/src/sys/pal/uefi/mod.rs | 2 +- library/std/src/sys/pal/uefi/system_time.rs | 151 +++++++++++++++ library/std/src/sys/time/mod.rs | 4 + .../sys/{pal/uefi/time.rs => time/uefi.rs} | 172 +----------------- 5 files changed, 168 insertions(+), 168 deletions(-) create mode 100644 library/std/src/sys/pal/uefi/system_time.rs rename library/std/src/sys/{pal/uefi/time.rs => time/uefi.rs} (52%) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index a1bb0c6e828bd..8135519317a02 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -580,7 +580,8 @@ mod uefi_fs { use crate::path::Path; use crate::ptr::NonNull; use crate::sys::pal::helpers::{self, UefiBox}; - use crate::sys::time::{self, SystemTime}; + use crate::sys::pal::system_time; + use crate::sys::time::SystemTime; pub(crate) struct File { protocol: NonNull, @@ -879,7 +880,7 @@ mod uefi_fs { /// conversion to SystemTime, we use the current time to get the timezone in such cases. pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> Option { time.timezone = if time.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE { - time::system_time_internal::now().timezone + system_time::now().timezone } else { time.timezone }; @@ -888,7 +889,7 @@ mod uefi_fs { /// Convert to UEFI Time with the current timezone. pub(crate) fn systemtime_to_uefi(time: SystemTime) -> r_efi::efi::Time { - let now = time::system_time_internal::now(); + let now = system_time::now(); time.to_uefi_loose(now.timezone, now.daylight) } diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index b181d78c2345a..e4a8f50e4274d 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -15,7 +15,7 @@ pub mod helpers; pub mod os; -pub mod time; +pub mod system_time; #[cfg(test)] mod tests; diff --git a/library/std/src/sys/pal/uefi/system_time.rs b/library/std/src/sys/pal/uefi/system_time.rs new file mode 100644 index 0000000000000..557a49b27c2d1 --- /dev/null +++ b/library/std/src/sys/pal/uefi/system_time.rs @@ -0,0 +1,151 @@ +use r_efi::efi::{RuntimeServices, Time}; + +use super::helpers; +use crate::mem::MaybeUninit; +use crate::ptr::NonNull; +use crate::time::Duration; + +const SECS_IN_MINUTE: u64 = 60; +const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60; +const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24; +const SYSTEMTIME_TIMEZONE: i64 = -1440 * SECS_IN_MINUTE as i64; + +pub(crate) fn now() -> Time { + let runtime_services: NonNull = + helpers::runtime_services().expect("Runtime services are not available"); + let mut t: MaybeUninit