11#[ doc( no_inline) ]
2+ use std:: { any:: Any , fmt:: Display , mem:: MaybeUninit , result, thread} ;
3+
24pub use anyhow:: { self , Error } ;
3- use std:: mem:: MaybeUninit ;
4- use std:: result;
5- use std:: thread;
6- use std:: any:: Any ;
75use thiserror:: Error ;
86
9- use super :: IntoLisp ;
10- use super :: { Env , Value } ;
117use emacs_module:: * ;
12- use crate :: { symbol:: { self , IntoLispSymbol } , GlobalRef } ;
13- use crate :: call:: IntoLispArgs ;
8+
9+ use crate :: {
10+ Env , Value , IntoLisp ,
11+ GlobalRef ,
12+ symbol:: { self , IntoLispSymbol } ,
13+ call:: IntoLispArgs ,
14+ } ;
1415
1516// We use const instead of enum, in case Emacs add more exit statuses in the future.
1617// See https://github.com/rust-lang/rust/issues/36927
@@ -23,6 +24,38 @@ pub struct TempValue {
2324 raw : emacs_value ,
2425}
2526
27+ /// Defines new error signals.
28+ ///
29+ /// TODO: Document this properly.
30+ ///
31+ /// This macro can be used only once per Rust `mod`.
32+ #[ macro_export]
33+ macro_rules! define_errors {
34+ ( $( $name: ident $message: literal $( ( $( $parent: ident ) + ) ) ? ) * ) => {
35+ $crate:: global_refs! { __emrs_init_global_refs_to_error_symbols__( init_to_symbol) =>
36+ $( $name ) *
37+ }
38+
39+ #[ $crate:: deps:: ctor:: ctor]
40+ fn __emrs_define_errors__( ) {
41+ $crate:: init:: __CUSTOM_ERRORS__. try_lock( )
42+ . expect( "Failed to acquire a write lock on the list of initializers for custom error signals" )
43+ . push( :: std:: boxed:: Box :: new( |env| {
44+ $(
45+ env. define_error( $name, $message, [
46+ $(
47+ $(
48+ env. intern( $crate:: deps:: emacs_macros:: lisp_name!( $parent) ) ?
49+ ) ,+
50+ ) ?
51+ ] ) ?;
52+ ) *
53+ Ok ( ( ) )
54+ } ) ) ;
55+ }
56+ }
57+ }
58+
2659/// Error types generic to all Rust dynamic modules.
2760///
2861/// This list is intended to grow over time and it is not recommended to exhaustively match against
@@ -100,6 +133,7 @@ impl TempValue {
100133// XXX: Technically these are unsound, but they are necessary to use the `Fail` trait. We ensure
101134// safety by marking TempValue methods as unsafe.
102135unsafe impl Send for TempValue { }
136+
103137unsafe impl Sync for TempValue { }
104138
105139impl Env {
@@ -117,16 +151,14 @@ impl Env {
117151 Err ( ErrorKind :: Signal {
118152 symbol : unsafe { TempValue :: new ( symbol. assume_init ( ) ) } ,
119153 data : unsafe { TempValue :: new ( data. assume_init ( ) ) } ,
120- }
121- . into ( ) )
154+ } . into ( ) )
122155 }
123156 ( THROW , tag, value) => {
124157 self . non_local_exit_clear ( ) ;
125158 Err ( ErrorKind :: Throw {
126159 tag : unsafe { TempValue :: new ( tag. assume_init ( ) ) } ,
127160 value : unsafe { TempValue :: new ( value. assume_init ( ) ) } ,
128- }
129- . into ( ) )
161+ } . into ( ) )
130162 }
131163 _ => panic ! ( "Unexpected non local exit status {}" , status) ,
132164 }
@@ -163,7 +195,7 @@ impl Env {
163195 if let Err ( error) = m {
164196 m = match error. downcast :: < ErrorKind > ( ) {
165197 // TODO: Explain safety.
166- Ok ( err) => unsafe { return self . handle_known ( & * err) } ,
198+ Ok ( err) => unsafe { return self . handle_known ( & * err) ; } ,
167199 Err ( error) => Err ( error) ,
168200 }
169201 }
@@ -175,15 +207,15 @@ impl Env {
175207 }
176208 }
177209
178- pub ( crate ) fn define_errors ( & self ) -> Result < ( ) > {
210+ pub ( crate ) fn define_core_errors ( & self ) -> Result < ( ) > {
179211 // FIX: Make panics louder than errors, by somehow make sure that 'rust-panic is
180212 // not a sub-type of 'error.
181- self . define_error ( symbol:: rust_panic, "Rust panic" , ( symbol:: error, ) ) ?;
182- self . define_error ( symbol:: rust_error, "Rust error" , ( symbol:: error, ) ) ?;
213+ self . define_error ( symbol:: rust_panic, "Rust panic" , ( symbol:: error, ) ) ?;
214+ self . define_error ( symbol:: rust_error, "Rust error" , ( symbol:: error, ) ) ?;
183215 self . define_error (
184216 symbol:: rust_wrong_type_user_ptr,
185217 "Wrong type user-ptr" ,
186- ( symbol:: rust_error, self . intern ( "wrong-type-argument" ) ?)
218+ ( symbol:: rust_error, self . intern ( "wrong-type-argument" ) ?) ,
187219 ) ?;
188220 Ok ( ( ) )
189221 }
@@ -255,46 +287,21 @@ impl Env {
255287 }
256288}
257289
258- /// Emacs-specific extension methods for [`Result`].
290+ /// Emacs-specific extension methods for the standard library's [`Result`].
259291///
260- /// [`Result`]: type. Result.html
292+ /// [`Result`]: result:: Result
261293pub trait ResultExt < T , E > {
262- /// Unwraps a result, yielding the content of an [`Ok`].
263- ///
264- /// # Panics
265- ///
266- /// Panics if the value is an [`Err`], using a sensible panic value.
267- ///
268- /// If the underlying error is an [`ErrorKind`], it will be used as the value of the panic,
269- /// which makes the `#[defun]` behave as if the corresponding non-local exit was propagated.
270- /// Otherwise, tries to use [`Display`] to get a descriptive error message.
294+ /// Converts the error into a Lisp signal if this result is an [`Err`]. The first element of the
295+ /// associated signal data will be a string formatted with [`Display::fmt`].
271296 ///
272- /// This is useful when errors cannot be propagated using [`Result`], e.g. callbacks whose types
273- /// are dictated by 3rd-party libraries.
274- ///
275- /// # Safety
276- ///
277- /// The panic must not propagate across an FFI boundary, e.g. this must not be used in callbacks
278- /// that will be called by C code. See Rust's [`issue #52652`].
279- ///
280- /// [`Ok`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
281- /// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
282- /// [`ErrorKind`]: enum.ErrorKind.html
283- /// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
284- /// [`Result`]: type.Result.html
285- /// [`issue #52652`]: https://github.com/rust-lang/rust/issues/52652
286- #[ deprecated( since = "0.12.0" , note = "Use Result or a variable to track error instead" ) ]
287- unsafe fn unwrap_or_propagate ( self ) -> T ;
297+ /// If the result is an [`Ok`], it is returned unchanged.
298+ fn or_signal < ' e , S > ( self , env : & ' e Env , symbol : S ) -> Result < T > where S : IntoLispSymbol < ' e > ;
288299}
289300
290- impl < T > ResultExt < T , Error > for Result < T > {
291- #[ inline]
292- unsafe fn unwrap_or_propagate ( self ) -> T {
293- self . unwrap_or_else ( |error| {
294- match error. downcast :: < ErrorKind > ( ) {
295- Ok ( err) => panic ! ( err) ,
296- Err ( error) => panic ! ( "{}" , error) ,
297- } ;
298- } )
301+ impl < T , E : Display > ResultExt < T , E > for result:: Result < T , E > {
302+ fn or_signal < ' e , S > ( self , env : & ' e Env , symbol : S ) -> Result < T > where S : IntoLispSymbol < ' e > {
303+ self . or_else ( |err| env. signal ( symbol, (
304+ format ! ( "{}" , err) ,
305+ ) ) )
299306 }
300307}
0 commit comments