medea_macro/lib.rs
1#![cfg_attr(any(doc, test), doc = include_str!("../README.md"))]
2#![cfg_attr(not(any(doc, test)), doc = env!("CARGO_PKG_NAME"))]
3#![deny(nonstandard_style, rustdoc::all, trivial_casts, trivial_numeric_casts)]
4#![forbid(non_ascii_idents, unsafe_code)]
5#![warn(
6 clippy::absolute_paths,
7 clippy::allow_attributes,
8 clippy::allow_attributes_without_reason,
9 clippy::as_conversions,
10 clippy::as_pointer_underscore,
11 clippy::as_ptr_cast_mut,
12 clippy::assertions_on_result_states,
13 clippy::branches_sharing_code,
14 clippy::cfg_not_test,
15 clippy::clear_with_drain,
16 clippy::clone_on_ref_ptr,
17 clippy::coerce_container_to_any,
18 clippy::collection_is_never_read,
19 clippy::create_dir,
20 clippy::dbg_macro,
21 clippy::debug_assert_with_mut_call,
22 clippy::decimal_literal_representation,
23 clippy::default_union_representation,
24 clippy::derive_partial_eq_without_eq,
25 clippy::doc_include_without_cfg,
26 clippy::empty_drop,
27 clippy::empty_structs_with_brackets,
28 clippy::equatable_if_let,
29 clippy::empty_enum_variants_with_brackets,
30 clippy::exit,
31 clippy::expect_used,
32 clippy::fallible_impl_from,
33 clippy::filetype_is_file,
34 clippy::float_cmp_const,
35 clippy::fn_to_numeric_cast_any,
36 clippy::get_unwrap,
37 clippy::if_then_some_else_none,
38 clippy::imprecise_flops,
39 clippy::infinite_loop,
40 clippy::iter_on_empty_collections,
41 clippy::iter_on_single_items,
42 clippy::iter_over_hash_type,
43 clippy::iter_with_drain,
44 clippy::large_include_file,
45 clippy::large_stack_frames,
46 clippy::let_underscore_untyped,
47 clippy::literal_string_with_formatting_args,
48 clippy::lossy_float_literal,
49 clippy::map_err_ignore,
50 clippy::map_with_unused_argument_over_ranges,
51 clippy::mem_forget,
52 clippy::missing_assert_message,
53 clippy::missing_asserts_for_indexing,
54 clippy::missing_const_for_fn,
55 clippy::missing_docs_in_private_items,
56 clippy::module_name_repetitions,
57 clippy::multiple_inherent_impl,
58 clippy::multiple_unsafe_ops_per_block,
59 clippy::mutex_atomic,
60 clippy::mutex_integer,
61 clippy::needless_collect,
62 clippy::needless_pass_by_ref_mut,
63 clippy::needless_raw_strings,
64 clippy::non_zero_suggestions,
65 clippy::nonstandard_macro_braces,
66 clippy::option_if_let_else,
67 clippy::or_fun_call,
68 clippy::panic_in_result_fn,
69 clippy::partial_pub_fields,
70 clippy::pathbuf_init_then_push,
71 clippy::pedantic,
72 clippy::precedence_bits,
73 clippy::print_stderr,
74 clippy::print_stdout,
75 clippy::pub_without_shorthand,
76 clippy::rc_buffer,
77 clippy::rc_mutex,
78 clippy::read_zero_byte_vec,
79 clippy::redundant_clone,
80 clippy::redundant_test_prefix,
81 clippy::redundant_type_annotations,
82 clippy::renamed_function_params,
83 clippy::ref_patterns,
84 clippy::rest_pat_in_fully_bound_structs,
85 clippy::return_and_then,
86 clippy::same_name_method,
87 clippy::semicolon_inside_block,
88 clippy::set_contains_or_insert,
89 clippy::shadow_unrelated,
90 clippy::significant_drop_in_scrutinee,
91 clippy::significant_drop_tightening,
92 clippy::single_option_map,
93 clippy::str_to_string,
94 clippy::string_add,
95 clippy::string_lit_as_bytes,
96 clippy::string_lit_chars_any,
97 clippy::string_slice,
98 clippy::suboptimal_flops,
99 clippy::suspicious_operation_groupings,
100 clippy::suspicious_xor_used_as_pow,
101 clippy::tests_outside_test_module,
102 clippy::todo,
103 clippy::too_long_first_doc_paragraph,
104 clippy::trailing_empty_array,
105 clippy::transmute_undefined_repr,
106 clippy::trivial_regex,
107 clippy::try_err,
108 clippy::undocumented_unsafe_blocks,
109 clippy::unimplemented,
110 clippy::uninhabited_references,
111 clippy::unnecessary_safety_comment,
112 clippy::unnecessary_safety_doc,
113 clippy::unnecessary_self_imports,
114 clippy::unnecessary_struct_initialization,
115 clippy::unused_peekable,
116 clippy::unused_result_ok,
117 clippy::unused_trait_names,
118 clippy::unwrap_in_result,
119 clippy::unwrap_used,
120 clippy::use_debug,
121 clippy::use_self,
122 clippy::useless_let_if_seq,
123 clippy::verbose_file_reads,
124 clippy::volatile_composites,
125 clippy::while_float,
126 clippy::wildcard_enum_match_arm,
127 ambiguous_negative_literals,
128 closure_returning_async_block,
129 future_incompatible,
130 impl_trait_redundant_captures,
131 let_underscore_drop,
132 macro_use_extern_crate,
133 meta_variable_misuse,
134 missing_copy_implementations,
135 missing_debug_implementations,
136 missing_docs,
137 redundant_lifetimes,
138 rust_2018_idioms,
139 single_use_lifetimes,
140 unit_bindings,
141 unnameable_types,
142 unreachable_pub,
143 unstable_features,
144 unused,
145 variant_size_differences
146)]
147
148mod caused;
149mod dart_bridge;
150#[cfg(feature = "dart-codegen")]
151mod dart_codegen;
152mod dispatchable;
153mod enum_delegate;
154mod watchers;
155
156#[cfg(test)]
157use async_trait as _;
158#[cfg(test)]
159use medea_jason as _;
160use proc_macro::TokenStream;
161
162/// Delegates function calls to enum variants field.
163/// Variants are expected to have only one field.
164///
165/// # How to use
166///
167/// ```rust
168/// use medea_macro::enum_delegate;
169///
170/// #[enum_delegate(pub fn as_str(&self) -> &str)]
171/// #[enum_delegate(pub fn push_str(&mut self, arg: &str))]
172/// enum MyEnum {
173/// Foo(String),
174/// Bar(String),
175/// }
176///
177/// let mut foo = MyEnum::Foo(String::from("foo"));
178/// foo.push_str("_bar");
179/// assert_eq!(foo.as_str(), "foo_bar")
180/// ```
181///
182/// # Extended example
183///
184/// ```rust
185/// use medea_macro::enum_delegate;
186///
187/// struct SomeState;
188/// struct AnotherState;
189///
190/// struct Context {
191/// some_value: i32,
192/// }
193///
194/// struct Peer<S> {
195/// context: Context,
196/// state: S,
197/// }
198///
199/// impl<T> Peer<T> {
200/// pub fn some_value(&self) -> i32 {
201/// self.context.some_value
202/// }
203///
204/// pub fn function_with_additional_args(&self, some_arg: i32) -> i32 {
205/// some_arg
206/// }
207///
208/// pub fn mutable_function(&mut self) -> i32 {
209/// let old_value = self.context.some_value;
210/// self.context.some_value = 1000;
211/// old_value
212/// }
213/// }
214///
215/// #[enum_delegate(pub fn some_value(&self) -> i32)]
216/// #[enum_delegate(
217/// pub fn function_with_additional_args(&self, some_arg: i32) -> i32
218/// )]
219/// #[enum_delegate(pub fn mutable_function(&mut self) -> i32)]
220/// enum PeerStateMachine {
221/// SomeState(Peer<SomeState>),
222/// AnotherState(Peer<AnotherState>),
223/// }
224///
225/// let mut peer = PeerStateMachine::SomeState(Peer {
226/// context: Context { some_value: 10 },
227/// state: SomeState,
228/// });
229///
230/// assert_eq!(peer.some_value(), 10);
231///
232/// assert_eq!(peer.function_with_additional_args(100), 100);
233///
234/// assert_eq!(peer.mutable_function(), 10);
235/// assert_eq!(peer.some_value(), 1000);
236/// ```
237#[proc_macro_attribute]
238pub fn enum_delegate(args: TokenStream, input: TokenStream) -> TokenStream {
239 enum_delegate::derive(&args, input)
240 .unwrap_or_else(|e| e.to_compile_error().into())
241}
242
243/// Generates a `*Handler` trait and dispatching function for some event,
244/// represented as `enum`.
245///
246/// # How to use
247///
248/// ### 1. Declare `enum` for event variants and a `struct` to handle them.
249///
250/// ```rust
251/// use medea_macro::dispatchable;
252///
253/// #[dispatchable]
254/// enum Event {
255/// Some { new_bar: i32 },
256/// Another,
257/// UnnamedVariant(i32, i32),
258/// }
259///
260/// struct Foo {
261/// bar: i32,
262/// baz: i32,
263/// }
264/// ```
265///
266/// ### 2. Implement handler for your `struct`.
267///
268/// For the given `enum` macro generates a unique trait by adding `Handler`
269/// to the end of its name. Each method of trait is created by `snake_case`'ing
270/// `enum` variants and adding `on_` prefix.
271///
272/// `type Output` is a type which will be returned from all functions of
273/// `EventHandler` trait.
274///
275/// ```rust
276/// # use medea_macro::dispatchable;
277/// #
278/// # #[dispatchable]
279/// # enum Event {
280/// # Some { new_bar: i32 },
281/// # Another,
282/// # UnnamedVariant(i32, i32),
283/// # }
284/// #
285/// # struct Foo {
286/// # bar: i32,
287/// # baz: i32,
288/// # }
289/// #
290/// impl EventHandler for Foo {
291/// type Output = i32;
292///
293/// fn on_some(&mut self, new_bar: i32) -> Self::Output {
294/// self.bar = new_bar;
295/// self.bar
296/// }
297///
298/// fn on_another(&mut self) -> Self::Output {
299/// self.bar = 2;
300/// self.bar
301/// }
302///
303/// fn on_unnamed_variant(&mut self, data: (i32, i32)) -> Self::Output {
304/// self.bar = data.0;
305/// self.baz = data.1;
306/// self.bar
307/// }
308/// }
309/// ```
310///
311/// ### 3. Dispatch event with handler
312///
313/// For the given `enum` macro generates `dispatch_with()` method to dispatch
314/// `enum` with a given handler.
315///
316/// ```rust
317/// # use medea_macro::dispatchable;
318/// #
319/// # #[dispatchable]
320/// # enum Event {
321/// # Some { new_bar: i32 },
322/// # Another,
323/// # UnnamedVariant(i32, i32),
324/// # }
325/// #
326/// # struct Foo {
327/// # bar: i32,
328/// # baz: i32,
329/// # }
330/// #
331/// # impl EventHandler for Foo {
332/// # type Output = i32;
333/// #
334/// # fn on_some(&mut self, new_bar: i32) -> Self::Output {
335/// # self.bar = new_bar;
336/// # self.bar
337/// # }
338/// #
339/// # fn on_another(&mut self) -> Self::Output {
340/// # self.bar = 2;
341/// # self.bar
342/// # }
343/// #
344/// # fn on_unnamed_variant(&mut self, data: (i32, i32)) -> Self::Output {
345/// # self.bar = data.0;
346/// # self.baz = data.1;
347/// # self.bar
348/// # }
349/// # }
350/// #
351/// #
352/// let mut foo = Foo { bar: 0, baz: 0 };
353///
354/// let bar = Event::Some { new_bar: 1 }.dispatch_with(&mut foo);
355/// assert_eq!(foo.bar, 1);
356/// assert_eq!(bar, 1);
357///
358/// let bar = Event::Another.dispatch_with(&mut foo);
359/// assert_eq!(foo.bar, 2);
360/// assert_eq!(bar, 2);
361///
362/// let bar = Event::UnnamedVariant(3, 3).dispatch_with(&mut foo);
363/// assert_eq!(foo.bar, 3);
364/// assert_eq!(foo.baz, 3);
365/// assert_eq!(bar, 3);
366/// ```
367///
368/// # Customize `self` type in handler functions (optional)
369///
370/// By default, all handler functions take `&mut Self`, if this doesn't suit
371/// your case, then you can specify the method receiver manually:
372/// `#[dispatchable(self: Rc<Self>)]`, `#[dispatchable(self: &Self)]`.
373///
374/// You can use any type that is a valid `self` receiver, e.g. `self`, `&self`,
375/// `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or
376/// `self: Pin<P>` (where P is one of the previous, except `Self`).
377///
378/// ```rust
379/// # use std::rc::Rc;
380/// use medea_macro::dispatchable;
381///
382/// #[dispatchable(self: Rc<Self>)]
383/// enum Event {
384/// Variant,
385/// }
386///
387/// struct Foo;
388/// impl EventHandler for Foo {
389/// type Output = ();
390///
391/// fn on_variant(self: Rc<Self>) {}
392/// }
393///
394/// let foo = Rc::new(Foo);
395///
396/// Event::Variant.dispatch_with(foo);
397/// ```
398///
399/// # Async handlers (optional)
400///
401/// It's possible to make handler methods `async`. Rust doesn't support `async`
402/// trait methods at the moment, that's why [`async_trait`] is used.
403///
404/// ```rust
405/// use async_trait::async_trait;
406/// use medea_macro::dispatchable;
407///
408/// #[dispatchable(async_trait(?Send))]
409/// enum Event {
410/// Variant,
411/// }
412///
413/// struct Foo;
414/// #[async_trait(?Send)]
415/// impl EventHandler for Foo {
416/// type Output = ();
417///
418/// async fn on_variant(&mut self) {}
419/// }
420///
421/// let mut foo = Foo;
422///
423/// Event::Variant.dispatch_with(&mut foo);
424/// ```
425///
426/// [`async_trait`]: https://docs.rs/async-trait
427#[proc_macro_attribute]
428pub fn dispatchable(args: TokenStream, input: TokenStream) -> TokenStream {
429 let enum_item = syn::parse_macro_input!(input as dispatchable::Item);
430 let args = syn::parse_macro_input!(args as dispatchable::Args);
431 dispatchable::expand(enum_item, &args)
432}
433
434/// Generates `ComponentState` implementation on provided `impl`.
435///
436/// # Usage
437///
438/// ```rust,ignore
439/// use std::rc::Rc;
440///
441/// use medea_jason::utils::Component;
442/// use medea_macro::{watchers, watch};
443///
444/// struct SenderState {
445/// muted: ObservableCell<bool>,
446/// enabled: ObservableCell<bool>,
447/// }
448///
449/// struct Sender;
450///
451/// type SenderComponent = Component<SenderState, Sender>;
452///
453/// #[watchers]
454/// impl SenderComponent {
455/// #[watch(self.muted.subscribe())]
456/// async fn muted_change_watcher(
457/// ctx: Rc<Sender>,
458/// state: Rc<SenderState>,
459/// new_muted_val: bool
460/// ) -> Result<(), ()> {
461/// Ok(())
462/// }
463///
464/// #[watch(self.enabled.subscribe())]
465/// async fn enabled_change_watcher(
466/// ctx: Rc<Sender>,
467/// state: Rc<SenderState>,
468/// new_enabled_val: bool,
469/// ) -> Result<(), ()> {
470/// Ok(())
471/// }
472/// }
473/// ```
474///
475/// ## `SenderComponent` implementation after macro expansion
476///
477/// ```rust,ignore
478/// impl SenderComponent {
479/// async fn muted_change_watcher(
480/// sender: Rc<Sender>,
481/// state: Rc<SenderState>,
482/// new_muted_val: bool
483/// ) -> Result<(), ()> {
484/// Ok(())
485/// }
486///
487/// async fn enabled_change_watcher(
488/// sender: Rc<Sender>,
489/// state: Rc<SenderState>,
490/// new_enabled_val: bool,
491/// ) -> Result<(), ()> {
492/// Ok(())
493/// }
494/// }
495///
496/// impl ComponentState<Sender> for SenderState {
497/// fn spawn_watchers(&self, s: &mut WatchersSpawner<SenderState, Sender>) {
498/// s.spawn(
499/// self.muted.subscribe(),
500/// SenderComponent::muted_change_watcher,
501/// );
502/// s.spawn(
503/// self.enabled.subscribe(),
504/// SenderComponent::enabled_change_watcher,
505/// );
506/// }
507/// }
508/// ```
509///
510/// __Note__: `ComponentState` implementation is simplified in this example
511/// for better readability.
512///
513/// In reality object and state types will be obtained by casting
514/// `SenderComponent` to the `ComponentTypes` trait and getting types from it.
515#[proc_macro_attribute]
516pub fn watchers(_: TokenStream, input: TokenStream) -> TokenStream {
517 watchers::expand(syn::parse_macro_input!(input))
518 .unwrap_or_else(|e| e.to_compile_error().into())
519}
520
521/// Generate implementation of `Caused` trait for errors represented as enum.
522///
523/// # How to use
524///
525/// ### 1. Declare custom error and enum for error variants.
526///
527/// The `cause()` method returns error if nested error has its type declared
528/// as an argument of the attribute `#[cause(error = path::to::Error)]` or the
529/// error type is assumed to be imported as `Error`.
530///
531/// ```rust
532/// use medea_jason::utils::Caused;
533///
534/// struct MyError;
535///
536/// #[derive(Caused)]
537/// #[cause(error = MyError)]
538/// enum FooError {
539/// Internal,
540/// MyError(MyError),
541/// }
542///
543/// let err = FooError::Internal;
544/// assert!(err.cause().is_none());
545///
546/// let err = FooError::MyError(MyError {});
547/// assert!(err.cause().is_some());
548/// ```
549///
550/// If enum variant has attribute `#[cause]` it will call the `cause()`
551/// method on nested error.
552///
553/// ```rust
554/// # use medea_jason::utils::Caused;
555/// #
556/// # struct MyError;
557/// #
558/// # #[derive(Caused)]
559/// # #[cause(error = MyError)]
560/// # enum FooError {
561/// # Internal,
562/// # MyError(MyError),
563/// # }
564/// #
565/// #[derive(Caused)]
566/// #[cause(error = MyError)]
567/// enum BarError {
568/// Foo(#[cause] FooError),
569/// }
570///
571/// let err = BarError::Foo(FooError::Internal);
572/// assert!(err.cause().is_none());
573///
574/// let err = BarError::Foo(FooError::MyError(MyError {}));
575/// assert!(err.cause().is_some());
576/// ```
577#[proc_macro_derive(Caused, attributes(cause))]
578pub fn derive_caused(input: TokenStream) -> TokenStream {
579 syn::parse::<syn::DeriveInput>(input)
580 .and_then(|i| {
581 let mut s = synstructure::Structure::try_new(&i)?;
582 caused::derive(&mut s)
583 })
584 .unwrap_or_else(|e| e.to_compile_error())
585 .into()
586}
587
588/// Generates code for `extern` Dart functions registration and calling.
589///
590/// # Usage
591///
592/// ## Macro call
593///
594/// ```ignore
595/// // Code will be generated in the `peer_connection` module, also you can
596/// // control visibility of this module with a visibility modifier (`pub`).
597/// //
598/// // Module name will be used as a prefix for a registration function.
599/// #[dart_bridge]
600/// mod peer_connection {
601/// use dart_sys::Dart_Handle;
602///
603/// use crate::platform::Error;
604///
605/// extern "C" {
606/// // This documentation will be injected to the generated
607/// // extern function caller:
608///
609/// /// Returns newly created SDP offer of the provided
610/// /// `PeerConnection`.
611/// fn create_offer(peer: Dart_Handle) -> Result<Dart_Handle, Error>;
612///
613/// /// Returns a newly created SDP answer of the provided
614/// /// `PeerConnection`.
615/// fn create_answer(peer: Dart_Handle) -> Result<Dart_Handle, Error>;
616/// }
617/// }
618/// ```
619///
620/// ## Example of the generated code
621///
622/// ```ignore
623/// #[automatically_derived]
624/// mod peer_connection {
625/// use dart_sys::Dart_Handle;
626///
627/// use crate::platform::Error;
628///
629/// type PeerConnectionCreateOfferFunction =
630/// extern "C" fn(peer: Dart_Handle) -> Dart_Handle;
631/// type PeerConnectionCreateAnswerFunction =
632/// extern "C" fn(peer: Dart_Handle) -> Dart_Handle;
633///
634/// static PEER_CONNECTION__CREATE_OFFER__FUNCTION: ::std::sync::OnceLock<
635/// ::send_wrapper::SendWrapper<PeerConnectionCreateOfferFunction>,
636/// > = ::std::sync::OnceLock::new();
637///
638/// static PEER_CONNECTION__CREATE_ANSWER__FUNCTION: ::std::sync::OnceLock<
639/// ::send_wrapper::SendWrapper<PeerConnectionCreateAnswerFunction>,
640/// > = ::std::sync::OnceLock::new();
641///
642/// static PEER_CONNECTION__CREATE_OFFER__ERROR: ::std::sync::LazyLock<
643/// ::send_wrapper::SendWrapper<::std::cell::RefCell<Option<Error>>>,
644/// > = ::std::sync::LazyLock::new(|| {
645/// ::send_wrapper::SendWrapper::new(::std::cell::RefCell::new(None))
646/// });
647///
648/// static PEER_CONNECTION__CREATE_ANSWER__ERROR: ::std::sync::LazyLock<
649/// ::send_wrapper::SendWrapper<::std::cell::RefCell<Option<Error>>>,
650/// > = ::std::sync::LazyLock::new(|| {
651/// ::send_wrapper::SendWrapper::new(::std::cell::RefCell::new(None))
652/// });
653///
654/// #[unsafe(no_mangle)]
655/// pub unsafe extern "C" fn register_peer_connection(
656/// create_offer: PeerConnectionCreateOfferFunction,
657/// create_answer: PeerConnectionCreateAnswerFunction,
658/// ) {
659/// PEER_CONNECTION__CREATE_OFFER__FUNCTION
660/// .set(::send_wrapper::SendWrapper::new(create_offer))
661/// .expect(
662/// "PEER_CONNECTION__CREATE_OFFER__FUNCTION \
663/// can only be set once",
664/// );
665/// PEER_CONNECTION__CREATE_ANSWER__FUNCTION
666/// .set(::send_wrapper::SendWrapper::new(create_answer))
667/// .expect(
668/// "PEER_CONNECTION__CREATE_ANSWER__FUNCTION \
669/// can only be set once",
670/// );
671/// }
672///
673/// /// Error setter for the `create_offer` function
674/// #[unsafe(no_mangle)]
675/// pub unsafe extern "C" fn peer_connection__create_offer__set_error(
676/// err: Dart_Handle,
677/// ) {
678/// _ = PEER_CONNECTION__CREATE_OFFER__ERROR.replace(
679/// Some(Error::from_handle(err))
680/// );
681/// }
682///
683/// /// Error setter for the `create_answer` function.
684/// #[unsafe(no_mangle)]
685/// pub unsafe extern "C" fn peer_connection__create_answer__set_error(
686/// err: Dart_Handle,
687/// ) {
688/// _ = PEER_CONNECTION__CREATE_ANSWER__ERROR.replace(
689/// Some(Error::from_handle(err))
690/// );
691/// }
692///
693/// /// Returns newly created SDP offer of the provided `PeerConnection`.
694/// pub unsafe fn create_offer(
695/// peer: Dart_Handle,
696/// ) -> Result<Dart_Handle, Error> {
697/// let res = (PEER_CONNECTION__CREATE_OFFER__FUNCTION
698/// .get()
699/// .as_ref()
700/// .expect("PEER_CONNECTION__CREATE_OFFER__FUNCTION is not set"))
701/// (peer);
702/// if let Some(e) = PEER_CONNECTION__CREATE_OFFER__ERROR
703/// .borrow_mut()
704/// .take()
705/// {
706/// Err(e)
707/// } else {
708/// Ok(res)
709/// }
710/// }
711///
712/// /// Returns a newly created SDP answer of the provided
713/// /// `PeerConnection`.
714/// pub unsafe fn create_answer(
715/// peer: Dart_Handle,
716/// ) -> Result<Dart_Handle, Error> {
717/// let res = (PEER_CONNECTION__CREATE_ANSWER__FUNCTION
718/// .get()
719/// .as_ref()
720/// .expect("PEER_CONNECTION__CREATE_ANSWER__FUNCTION is not set"))
721/// (peer);
722/// if let Some(e) = PEER_CONNECTION__CREATE_ANSWER__ERROR
723/// .borrow_mut()
724/// .take()
725/// {
726/// Err(e)
727/// } else {
728/// Ok(res)
729/// }
730/// }
731/// }
732/// ```
733///
734/// ## Generated code usage
735///
736/// ```ignore
737/// struct PeerConnection(Dart_Handle);
738///
739/// impl PeerConnection {
740/// pub async fn create_offer(&self) -> RtcPeerConnectionResult<String> {
741/// let fut = unsafe {
742/// peer_connection::create_offer(self.handle.get())
743/// }.unwrap();
744///
745/// unsafe { FutureFromDart::execute(fut) }
746/// .await
747/// .map_err(RtcPeerConnectionError::CreateOfferFailed)
748/// }
749///
750/// pub async fn create_answer(&self) -> RtcPeerConnectionResult<String> {
751/// let fut = unsafe {
752/// peer_connection::create_offer(self.handle.get())
753/// }.unwrap();
754///
755/// unsafe { FutureFromDart::execute(fut) }
756/// .await
757/// .map_err(RtcPeerConnectionError::CreateAnswerFailed)
758/// }
759/// }
760///
761/// pub enum RtcPeerConnectionError {
762/// CreateOfferFailed(platform::Error),
763/// CreateAnswerFailed(platform::Error),
764/// }
765///
766/// pub type RtcPeerConnectionResult<T> = Result<T, RtcPeerConnectionError>;
767/// ```
768/// ## Dart side code
769///
770/// Also, you need to call registration functions on Dart side:
771/// ```dart
772/// dl.lookupFunction<Void Function(Pointer), void Function(Pointer)>(
773/// 'register_peer_connection')(
774/// createOffer_native,
775/// createAnswer_native,
776/// );
777/// ```
778#[proc_macro_attribute]
779pub fn dart_bridge(args: TokenStream, input: TokenStream) -> TokenStream {
780 dart_bridge::expand(args.into(), input.into())
781 .map_or_else(|e| e.to_compile_error().into(), Into::into)
782}