Skip to main content

fory_core/serializer/
trait_object.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::any::Any;
19
20/// Object-safe access to a concrete target's [`Any`] identity.
21///
22/// Application traits serialized by [`crate::register_trait_type!`] extend this
23/// trait instead of extending [`crate::Serializer`].
24pub trait ForyObject: Any {
25    fn as_any(&self) -> &dyn Any;
26}
27
28impl<T: Any> ForyObject for T {
29    #[inline(always)]
30    fn as_any(&self) -> &dyn Any {
31        self
32    }
33}
34
35/// Generates serializers for a closed set of concrete application-trait targets.
36///
37/// The listed types are runtime target types. Their registered ordinary serializer,
38/// external structural serializer, or manual serializer determines wire behavior.
39///
40/// ```rust,ignore
41/// use fory::{register_trait_type, ForyObject};
42///
43/// trait Animal: ForyObject {
44///     fn name(&self) -> &str;
45/// }
46///
47/// register_trait_type!(Animal, Dog, third_party::Cat);
48/// ```
49///
50/// Use `sync` when the application trait and all targets are `Send + Sync`:
51///
52/// ```rust,ignore
53/// register_trait_type!(sync Animal, Dog, third_party::Cat);
54/// ```
55///
56/// Generated serializer and codec names are private by default. Prefix the trait
57/// with a Rust visibility when those names must be exported:
58///
59/// ```rust,ignore
60/// register_trait_type!(pub Animal, Dog, third_party::Cat);
61/// register_trait_type!(pub sync SharedAnimal, Dog, third_party::Cat);
62/// ```
63#[macro_export]
64macro_rules! register_trait_type {
65    ($vis:vis sync $trait_name:ident, $($target:ty),+ $(,)?) => {
66        $crate::register_trait_type!(@dispatch $trait_name, $($target),+);
67        $crate::register_trait_type!(@box [$vis] $trait_name, $($target),+);
68        $crate::register_trait_type!(@rc [$vis] $trait_name, $($target),+);
69        $crate::register_trait_type!(@arc [$vis] $trait_name, $($target),+);
70    };
71
72    ($vis:vis $trait_name:ident, $($target:ty),+ $(,)?) => {
73        $crate::register_trait_type!(@dispatch $trait_name, $($target),+);
74        $crate::register_trait_type!(@box [$vis] $trait_name, $($target),+);
75        $crate::register_trait_type!(@rc [$vis] $trait_name, $($target),+);
76    };
77
78    (@dispatch $trait_name:ident, $($target:ty),+) => {
79        $crate::paste::paste! {
80            #[allow(dead_code)]
81            struct [<$trait_name ForyDispatch>];
82
83            #[allow(dead_code)]
84            impl [<$trait_name ForyDispatch>] {
85                #[inline(always)]
86                fn any_ref(value: &dyn $trait_name) -> &dyn std::any::Any {
87                    <dyn $trait_name as $crate::ForyObject>::as_any(value)
88                }
89
90                #[inline(always)]
91                fn ensure_member(
92                    target_type_id: std::any::TypeId,
93                ) -> Result<(), $crate::Error> {
94                    if !($(target_type_id == std::any::TypeId::of::<$target>())||+) {
95                        return Err(Self::unlisted(target_type_id));
96                    }
97                    Ok(())
98                }
99
100                #[inline(always)]
101                fn checked_any(
102                    value: &dyn $trait_name,
103                ) -> Result<&dyn std::any::Any, $crate::Error> {
104                    let any = Self::any_ref(value);
105                    Self::ensure_member(any.type_id())?;
106                    Ok(any)
107                }
108
109                #[inline(always)]
110                fn target_id(
111                    type_info: &$crate::TypeInfo,
112                ) -> Result<std::any::TypeId, $crate::Error> {
113                    type_info
114                        .get_harness()
115                        .target_type_id()
116                        .ok_or_else(Self::missing)
117                }
118
119                #[inline(always)]
120                fn check_type_info(
121                    target_type_id: std::any::TypeId,
122                    type_info: &$crate::TypeInfo,
123                ) -> Result<(), $crate::Error> {
124                    $crate::serializer::any::check_erased_target_type(type_info)?;
125                    let resolved_target_type_id = Self::target_id(type_info)?;
126                    if resolved_target_type_id != target_type_id {
127                        return Err(Self::downcast(
128                            resolved_target_type_id,
129                            target_type_id,
130                        ));
131                    }
132                    Ok(())
133                }
134
135                #[inline(always)]
136                fn resolve_type_info(
137                    context: &mut $crate::WriteContext,
138                    target_type_id: std::any::TypeId,
139                ) -> Result<std::rc::Rc<$crate::TypeInfo>, $crate::Error> {
140                    let type_info = context.get_target_type_info(&target_type_id)?;
141                    Self::check_type_info(target_type_id, &type_info)?;
142                    Ok(type_info)
143                }
144
145                #[inline(always)]
146                fn write_type_info_value(
147                    context: &mut $crate::WriteContext,
148                    target_type_id: std::any::TypeId,
149                ) -> Result<std::rc::Rc<$crate::TypeInfo>, $crate::Error> {
150                    Self::ensure_member(target_type_id)?;
151                    let type_info = Self::resolve_type_info(context, target_type_id)?;
152                    context.write_resolved_type_info(
153                        $crate::TypeId::UNKNOWN as u32,
154                        type_info,
155                    )
156                }
157
158                #[inline(always)]
159                fn write_harness(
160                    any: &dyn std::any::Any,
161                    context: &mut $crate::WriteContext,
162                    type_info: &std::rc::Rc<$crate::TypeInfo>,
163                ) -> Result<(), $crate::Error> {
164                    type_info.get_harness().write_data(any, context)
165                }
166
167                #[inline(always)]
168                fn write_checked(
169                    any: &dyn std::any::Any,
170                    context: &mut $crate::WriteContext,
171                    write_type_info: bool,
172                ) -> Result<(), $crate::Error> {
173                    let type_info = Self::resolve_type_info(context, any.type_id())?;
174                    let type_info = if write_type_info {
175                        context.write_resolved_type_info(
176                            $crate::TypeId::UNKNOWN as u32,
177                            type_info,
178                        )?
179                    } else {
180                        type_info
181                    };
182                    Self::write_harness(any, context, &type_info)
183                }
184
185                #[inline(always)]
186                fn write_data(
187                    value: &dyn $trait_name,
188                    context: &mut $crate::WriteContext,
189                    write_type_info: bool,
190                ) -> Result<(), $crate::Error> {
191                    let any = Self::checked_any(value)?;
192                    Self::write_checked(any, context, write_type_info)
193                }
194
195                #[inline(always)]
196                fn read_box(
197                    context: &mut $crate::ReadContext,
198                    type_info: &std::rc::Rc<$crate::TypeInfo>,
199                ) -> Result<Box<dyn $trait_name>, $crate::Error> {
200                    let target_type_id = Self::target_id(type_info)?;
201                    $crate::serializer::any::check_erased_target_type(type_info)?;
202                    $(
203                        if target_type_id == std::any::TypeId::of::<$target>() {
204                            let erased = type_info
205                                .get_harness()
206                                .read_box_any(context, type_info)?;
207                            let concrete = erased.downcast::<$target>().map_err(|value| {
208                                Self::downcast(target_type_id, value.as_ref().type_id())
209                            })?;
210                            let value: Box<dyn $trait_name> = concrete;
211                            return Ok(value);
212                        }
213                    )+
214                    Err(Self::unlisted(target_type_id))
215                }
216
217                #[inline(always)]
218                fn read_rc(
219                    context: &mut $crate::ReadContext,
220                    type_info: &std::rc::Rc<$crate::TypeInfo>,
221                ) -> Result<std::rc::Rc<dyn $trait_name>, $crate::Error> {
222                    let target_type_id = Self::target_id(type_info)?;
223                    $crate::serializer::any::check_erased_target_type(type_info)?;
224                    $(
225                        if target_type_id == std::any::TypeId::of::<$target>() {
226                            let erased = type_info
227                                .get_harness()
228                                .read_rc_any(context, type_info)?;
229                            let concrete = erased.downcast::<$target>().map_err(|value| {
230                                Self::downcast(target_type_id, value.as_ref().type_id())
231                            })?;
232                            let value: std::rc::Rc<dyn $trait_name> = concrete;
233                            return Ok(value);
234                        }
235                    )+
236                    Err(Self::unlisted(target_type_id))
237                }
238
239                #[cold]
240                #[inline(never)]
241                fn unlisted(target_type_id: std::any::TypeId) -> $crate::Error {
242                    $crate::Error::type_error(format!(
243                        "target TypeId {:?} is not listed for application trait {}",
244                        target_type_id,
245                        stringify!($trait_name),
246                    ))
247                }
248
249                #[cold]
250                #[inline(never)]
251                fn missing() -> $crate::Error {
252                    $crate::Error::type_error(format!(
253                        "application trait {} metadata has no checked local target registration",
254                        stringify!($trait_name),
255                    ))
256                }
257
258                #[cold]
259                #[inline(never)]
260                fn downcast(
261                    expected: std::any::TypeId,
262                    actual: std::any::TypeId,
263                ) -> $crate::Error {
264                    $crate::Error::type_error(format!(
265                        "application trait {} expected target TypeId {:?}, got {:?}",
266                        stringify!($trait_name),
267                        expected,
268                        actual,
269                    ))
270                }
271
272                #[cold]
273                #[inline(never)]
274                fn missing_ref(ref_id: u32) -> $crate::Error {
275                    $crate::Error::invalid_data(format!(
276                        "dyn {} reference {} not found",
277                        stringify!($trait_name),
278                        ref_id,
279                    ))
280                }
281            }
282        }
283    };
284
285    (@box [$vis:vis] $trait_name:ident, $($target:ty),+) => {
286        $crate::paste::paste! {
287            #[allow(dead_code)]
288            impl [<$trait_name ForyDispatch>] {
289                #[cold]
290                #[inline(never)]
291                fn null_box_value() -> $crate::Error {
292                    $crate::Error::invalid_ref(concat!(
293                        "Box<dyn ",
294                        stringify!($trait_name),
295                        "> cannot be null",
296                    ))
297                }
298
299                #[cold]
300                #[inline(never)]
301                fn missing_box_metadata() -> $crate::Error {
302                    $crate::Error::invalid_data(concat!(
303                        "Box<dyn ",
304                        stringify!($trait_name),
305                        "> requires concrete type metadata",
306                    ))
307                }
308            }
309
310            impl $crate::Serializer for Box<dyn $trait_name> {
311                type Target = Self;
312                #[inline(always)]
313                fn write_data(
314                    value: &Self,
315                    context: &mut $crate::WriteContext,
316                ) -> Result<(), $crate::Error> {
317                    [<$trait_name ForyDispatch>]::write_data(
318                        value.as_ref(),
319                        context,
320                        false,
321                    )
322                }
323
324                #[cold]
325                #[inline(never)]
326                fn read_data(
327                    _context: &mut $crate::ReadContext,
328                ) -> Result<Self, $crate::Error> {
329                    Err($crate::Error::not_allowed(concat!(
330                        "Box<dyn ",
331                        stringify!($trait_name),
332                        "> requires concrete type metadata",
333                    )))
334                }
335
336                #[inline(always)]
337                fn write_type_info_value(
338                    context: &mut $crate::WriteContext,
339                    target_type_id: std::any::TypeId,
340                ) -> Result<std::rc::Rc<$crate::TypeInfo>, $crate::Error> {
341                    [<$trait_name ForyDispatch>]::write_type_info_value(
342                        context,
343                        target_type_id,
344                    )
345                }
346
347                #[inline(always)]
348                fn write_with_type_info(
349                    value: &Self,
350                    context: &mut $crate::WriteContext,
351                    ref_mode: $crate::RefMode,
352                    type_info: &std::rc::Rc<$crate::TypeInfo>,
353                ) -> Result<(), $crate::Error> {
354                    let any = [<$trait_name ForyDispatch>]::checked_any(value.as_ref())?;
355                    [<$trait_name ForyDispatch>]::check_type_info(any.type_id(), type_info)?;
356                    if ref_mode != $crate::RefMode::None {
357                        context.writer.write_i8($crate::RefFlag::NotNullValue as i8);
358                    }
359                    [<$trait_name ForyDispatch>]::write_harness(
360                        any,
361                        context,
362                        type_info,
363                    )
364                }
365
366                #[inline(always)]
367                fn write(
368                    value: &Self,
369                    context: &mut $crate::WriteContext,
370                    ref_mode: $crate::RefMode,
371                    write_type_info: bool,
372                ) -> Result<(), $crate::Error> {
373                    let any = [<$trait_name ForyDispatch>]::checked_any(value.as_ref())?;
374                    if ref_mode != $crate::RefMode::None {
375                        context.writer.write_i8($crate::RefFlag::NotNullValue as i8);
376                    }
377                    [<$trait_name ForyDispatch>]::write_checked(
378                        any,
379                        context,
380                        write_type_info,
381                    )
382                }
383
384                #[inline(always)]
385                fn read(
386                    context: &mut $crate::ReadContext,
387                    ref_mode: $crate::RefMode,
388                    read_type_info: bool,
389                ) -> Result<Self, $crate::Error> {
390                    context.inc_depth()?;
391                    let result = (|| {
392                        if ref_mode != $crate::RefMode::None
393                            && context.reader.read_i8()?
394                                != $crate::RefFlag::NotNullValue as i8
395                        {
396                            return Err([<$trait_name ForyDispatch>]::null_box_value());
397                        }
398                        if !read_type_info {
399                            return Err([<$trait_name ForyDispatch>]::missing_box_metadata());
400                        }
401                        let type_info = context.read_any_type_info()?;
402                        [<$trait_name ForyDispatch>]::read_box(context, &type_info)
403                    })();
404                    context.dec_depth();
405                    result
406                }
407
408                #[inline(always)]
409                fn read_with_type_info(
410                    context: &mut $crate::ReadContext,
411                    ref_mode: $crate::RefMode,
412                    type_info: &std::rc::Rc<$crate::TypeInfo>,
413                ) -> Result<Self, $crate::Error> {
414                    context.inc_depth()?;
415                    let result = (|| {
416                        if ref_mode != $crate::RefMode::None
417                            && context.reader.read_i8()?
418                                != $crate::RefFlag::NotNullValue as i8
419                        {
420                            return Err([<$trait_name ForyDispatch>]::null_box_value());
421                        }
422                        [<$trait_name ForyDispatch>]::read_box(context, type_info)
423                    })();
424                    context.dec_depth();
425                    result
426                }
427
428                #[inline(always)]
429                fn write_type_info(
430                    _context: &mut $crate::WriteContext,
431                ) -> Result<(), $crate::Error> {
432                    Ok(())
433                }
434
435                #[inline(always)]
436                fn read_type_info(
437                    _context: &mut $crate::ReadContext,
438                ) -> Result<(), $crate::Error> {
439                    Ok(())
440                }
441
442                #[inline(always)]
443                fn static_type_id() -> $crate::TypeId {
444                    $crate::TypeId::UNKNOWN
445                }
446
447                #[inline(always)]
448                fn reserved_space() -> usize {
449                    $crate::type_id::SIZE_OF_REF_AND_TYPE
450                }
451
452                const IS_POLYMORPHIC: bool = true;
453
454                const IS_WRAPPER: bool = true;
455
456                #[inline(always)]
457                fn dynamic_type_id(
458                    value: &Self,
459                ) -> Result<Option<std::any::TypeId>, $crate::Error> {
460                    Ok(Some(
461                        [<$trait_name ForyDispatch>]::any_ref(value.as_ref()).type_id(),
462                    ))
463                }
464            }
465
466            $crate::register_trait_type!(
467                @codec
468                [$vis]
469                [<$trait_name BoxCodec>],
470                Box<dyn $trait_name>,
471                Box<dyn $trait_name>
472            );
473        }
474    };
475
476    (@rc [$vis:vis] $trait_name:ident, $($target:ty),+) => {
477        $crate::paste::paste! {
478            #[allow(dead_code)]
479            impl [<$trait_name ForyDispatch>] {
480                #[cold]
481                #[inline(never)]
482                fn null_rc_value() -> $crate::Error {
483                    $crate::Error::invalid_ref(concat!(
484                        "Rc<dyn ",
485                        stringify!($trait_name),
486                        "> cannot be null",
487                    ))
488                }
489
490                #[cold]
491                #[inline(never)]
492                fn missing_rc_metadata() -> $crate::Error {
493                    $crate::Error::invalid_data(concat!(
494                        "Rc<dyn ",
495                        stringify!($trait_name),
496                        "> requires concrete type metadata",
497                    ))
498                }
499            }
500
501            #[allow(dead_code)]
502            #[doc = concat!("Serializer for `Rc<dyn ", stringify!($trait_name), ">`.")]
503            $vis struct [<$trait_name RcSerializer>](std::marker::PhantomData<()>);
504
505            impl $crate::Serializer for [<$trait_name RcSerializer>] {
506                type Target = std::rc::Rc<dyn $trait_name>;
507                #[inline(always)]
508                fn write_data(
509                    value: &Self::Target,
510                    context: &mut $crate::WriteContext,
511                ) -> Result<(), $crate::Error> {
512                    [<$trait_name ForyDispatch>]::write_data(
513                        value.as_ref(),
514                        context,
515                        false,
516                    )
517                }
518
519                #[cold]
520                #[inline(never)]
521                fn read_data(
522                    _context: &mut $crate::ReadContext,
523                ) -> Result<Self::Target, $crate::Error> {
524                    Err($crate::Error::not_allowed(concat!(
525                        "Rc<dyn ",
526                        stringify!($trait_name),
527                        "> requires concrete type metadata",
528                    )))
529                }
530
531                #[inline(always)]
532                fn write_type_info_value(
533                    context: &mut $crate::WriteContext,
534                    target_type_id: std::any::TypeId,
535                ) -> Result<std::rc::Rc<$crate::TypeInfo>, $crate::Error> {
536                    [<$trait_name ForyDispatch>]::write_type_info_value(
537                        context,
538                        target_type_id,
539                    )
540                }
541
542                #[inline(always)]
543                fn write_with_type_info(
544                    value: &Self::Target,
545                    context: &mut $crate::WriteContext,
546                    ref_mode: $crate::RefMode,
547                    type_info: &std::rc::Rc<$crate::TypeInfo>,
548                ) -> Result<(), $crate::Error> {
549                    let any = [<$trait_name ForyDispatch>]::checked_any(value.as_ref())?;
550                    [<$trait_name ForyDispatch>]::check_type_info(any.type_id(), type_info)?;
551                    if ref_mode != $crate::RefMode::None
552                        && context
553                            .ref_writer
554                            .try_write_rc_ref(&mut context.writer, value)
555                    {
556                        return Ok(());
557                    }
558                    [<$trait_name ForyDispatch>]::write_harness(
559                        any,
560                        context,
561                        type_info,
562                    )
563                }
564
565                #[inline(always)]
566                fn write(
567                    value: &Self::Target,
568                    context: &mut $crate::WriteContext,
569                    ref_mode: $crate::RefMode,
570                    write_type_info: bool,
571                ) -> Result<(), $crate::Error> {
572                    let any = [<$trait_name ForyDispatch>]::checked_any(value.as_ref())?;
573                    if ref_mode != $crate::RefMode::None
574                        && context
575                            .ref_writer
576                            .try_write_rc_ref(&mut context.writer, value)
577                    {
578                        return Ok(());
579                    }
580                    [<$trait_name ForyDispatch>]::write_checked(
581                        any,
582                        context,
583                        write_type_info,
584                    )
585                }
586
587                #[inline(always)]
588                fn read(
589                    context: &mut $crate::ReadContext,
590                    ref_mode: $crate::RefMode,
591                    read_type_info: bool,
592                ) -> Result<Self::Target, $crate::Error> {
593                    let ref_flag = if ref_mode != $crate::RefMode::None {
594                        context.ref_reader.read_ref_flag(&mut context.reader)?
595                    } else {
596                        $crate::RefFlag::NotNullValue
597                    };
598                    match ref_flag {
599                        $crate::RefFlag::Null => {
600                            Err([<$trait_name ForyDispatch>]::null_rc_value())
601                        }
602                        $crate::RefFlag::Ref => {
603                            let ref_id =
604                                context.ref_reader.read_ref_id(&mut context.reader)?;
605                            context
606                                .ref_reader
607                                .get_rc_ref::<dyn $trait_name>(ref_id)
608                                .ok_or_else(|| {
609                                    [<$trait_name ForyDispatch>]::missing_ref(ref_id)
610                                })
611                        }
612                        $crate::RefFlag::NotNullValue => {
613                            context.inc_depth()?;
614                            let result = (|| {
615                                if !read_type_info {
616                                    return Err(
617                                        [<$trait_name ForyDispatch>]::missing_rc_metadata()
618                                    );
619                                }
620                                let type_info = context.read_any_type_info()?;
621                                [<$trait_name ForyDispatch>]::read_rc(context, &type_info)
622                            })();
623                            context.dec_depth();
624                            result
625                        }
626                        $crate::RefFlag::RefValue => {
627                            let ref_id = context.ref_reader.reserve_ref_id();
628                            context.inc_depth()?;
629                            let result = (|| {
630                                if !read_type_info {
631                                    return Err(
632                                        [<$trait_name ForyDispatch>]::missing_rc_metadata()
633                                    );
634                                }
635                                let type_info = context.read_any_type_info()?;
636                                [<$trait_name ForyDispatch>]::read_rc(context, &type_info)
637                            })();
638                            context.dec_depth();
639                            let value = result?;
640                            context.ref_reader.store_rc_ref_at(ref_id, value.clone());
641                            Ok(value)
642                        }
643                    }
644                }
645
646                #[inline(always)]
647                fn read_with_type_info(
648                    context: &mut $crate::ReadContext,
649                    ref_mode: $crate::RefMode,
650                    type_info: &std::rc::Rc<$crate::TypeInfo>,
651                ) -> Result<Self::Target, $crate::Error> {
652                    let ref_flag = if ref_mode != $crate::RefMode::None {
653                        context.ref_reader.read_ref_flag(&mut context.reader)?
654                    } else {
655                        $crate::RefFlag::NotNullValue
656                    };
657                    match ref_flag {
658                        $crate::RefFlag::Null => {
659                            Err([<$trait_name ForyDispatch>]::null_rc_value())
660                        }
661                        $crate::RefFlag::Ref => {
662                            let ref_id =
663                                context.ref_reader.read_ref_id(&mut context.reader)?;
664                            context
665                                .ref_reader
666                                .get_rc_ref::<dyn $trait_name>(ref_id)
667                                .ok_or_else(|| {
668                                    [<$trait_name ForyDispatch>]::missing_ref(ref_id)
669                                })
670                        }
671                        $crate::RefFlag::NotNullValue => {
672                            context.inc_depth()?;
673                            let result =
674                                [<$trait_name ForyDispatch>]::read_rc(context, type_info);
675                            context.dec_depth();
676                            result
677                        }
678                        $crate::RefFlag::RefValue => {
679                            let ref_id = context.ref_reader.reserve_ref_id();
680                            context.inc_depth()?;
681                            let result =
682                                [<$trait_name ForyDispatch>]::read_rc(context, type_info);
683                            context.dec_depth();
684                            let value = result?;
685                            context.ref_reader.store_rc_ref_at(ref_id, value.clone());
686                            Ok(value)
687                        }
688                    }
689                }
690
691                #[inline(always)]
692                fn write_type_info(
693                    _context: &mut $crate::WriteContext,
694                ) -> Result<(), $crate::Error> {
695                    Ok(())
696                }
697
698                #[inline(always)]
699                fn read_type_info(
700                    _context: &mut $crate::ReadContext,
701                ) -> Result<(), $crate::Error> {
702                    Ok(())
703                }
704
705                #[inline(always)]
706                fn static_type_id() -> $crate::TypeId {
707                    $crate::TypeId::UNKNOWN
708                }
709
710                #[inline(always)]
711                fn reserved_space() -> usize {
712                    $crate::type_id::SIZE_OF_REF_AND_TYPE
713                }
714
715                const IS_POLYMORPHIC: bool = true;
716
717                const IS_SHARED_REF: bool = true;
718
719                const IS_WRAPPER: bool = true;
720
721                #[inline(always)]
722                fn dynamic_type_id(
723                    value: &Self::Target,
724                ) -> Result<Option<std::any::TypeId>, $crate::Error> {
725                    Ok(Some(
726                        [<$trait_name ForyDispatch>]::any_ref(value.as_ref()).type_id(),
727                    ))
728                }
729            }
730
731            $crate::register_trait_type!(
732                @codec
733                [$vis]
734                [<$trait_name RcCodec>],
735                [<$trait_name RcSerializer>],
736                std::rc::Rc<dyn $trait_name>
737            );
738        }
739    };
740
741    (@arc [$vis:vis] $trait_name:ident, $($target:ty),+) => {
742        $crate::paste::paste! {
743            const _: () = {
744                fn assert_sync<T: ?Sized + Send + Sync>() {}
745                let _ = assert_sync::<dyn $trait_name>;
746                $(let _ = assert_sync::<$target>;)+
747            };
748
749            #[allow(dead_code)]
750            impl [<$trait_name ForyDispatch>] {
751                #[cold]
752                #[inline(never)]
753                fn null_arc_value() -> $crate::Error {
754                    $crate::Error::invalid_ref(concat!(
755                        "Arc<dyn ",
756                        stringify!($trait_name),
757                        "> cannot be null",
758                    ))
759                }
760
761                #[cold]
762                #[inline(never)]
763                fn missing_arc_metadata() -> $crate::Error {
764                    $crate::Error::invalid_data(concat!(
765                        "Arc<dyn ",
766                        stringify!($trait_name),
767                        "> requires concrete type metadata",
768                    ))
769                }
770
771                #[inline(always)]
772                fn read_arc(
773                    context: &mut $crate::ReadContext,
774                    type_info: &std::rc::Rc<$crate::TypeInfo>,
775                ) -> Result<std::sync::Arc<dyn $trait_name>, $crate::Error> {
776                    let target_type_id = Self::target_id(type_info)?;
777                    $crate::serializer::any::check_erased_target_type(type_info)?;
778                    $(
779                        if target_type_id == std::any::TypeId::of::<$target>() {
780                            let erased = type_info
781                                .get_harness()
782                                .read_arc_any(context, type_info)?;
783                            let concrete = erased.downcast::<$target>().map_err(|value| {
784                                Self::downcast(target_type_id, value.as_ref().type_id())
785                            })?;
786                            let value: std::sync::Arc<dyn $trait_name> = concrete;
787                            return Ok(value);
788                        }
789                    )+
790                    Err(Self::unlisted(target_type_id))
791                }
792            }
793
794            #[allow(dead_code)]
795            #[doc = concat!("Serializer for `Arc<dyn ", stringify!($trait_name), ">`.")]
796            $vis struct [<$trait_name ArcSerializer>](std::marker::PhantomData<()>);
797
798            impl $crate::Serializer for [<$trait_name ArcSerializer>] {
799                type Target = std::sync::Arc<dyn $trait_name>;
800                #[inline(always)]
801                fn write_data(
802                    value: &Self::Target,
803                    context: &mut $crate::WriteContext,
804                ) -> Result<(), $crate::Error> {
805                    [<$trait_name ForyDispatch>]::write_data(
806                        value.as_ref(),
807                        context,
808                        false,
809                    )
810                }
811
812                #[cold]
813                #[inline(never)]
814                fn read_data(
815                    _context: &mut $crate::ReadContext,
816                ) -> Result<Self::Target, $crate::Error> {
817                    Err($crate::Error::not_allowed(concat!(
818                        "Arc<dyn ",
819                        stringify!($trait_name),
820                        "> requires concrete type metadata",
821                    )))
822                }
823
824                #[inline(always)]
825                fn write_type_info_value(
826                    context: &mut $crate::WriteContext,
827                    target_type_id: std::any::TypeId,
828                ) -> Result<std::rc::Rc<$crate::TypeInfo>, $crate::Error> {
829                    [<$trait_name ForyDispatch>]::write_type_info_value(
830                        context,
831                        target_type_id,
832                    )
833                }
834
835                #[inline(always)]
836                fn write_with_type_info(
837                    value: &Self::Target,
838                    context: &mut $crate::WriteContext,
839                    ref_mode: $crate::RefMode,
840                    type_info: &std::rc::Rc<$crate::TypeInfo>,
841                ) -> Result<(), $crate::Error> {
842                    let any = [<$trait_name ForyDispatch>]::checked_any(value.as_ref())?;
843                    [<$trait_name ForyDispatch>]::check_type_info(any.type_id(), type_info)?;
844                    if ref_mode != $crate::RefMode::None
845                        && context
846                            .ref_writer
847                            .try_write_arc_ref(&mut context.writer, value)
848                    {
849                        return Ok(());
850                    }
851                    [<$trait_name ForyDispatch>]::write_harness(
852                        any,
853                        context,
854                        type_info,
855                    )
856                }
857
858                #[inline(always)]
859                fn write(
860                    value: &Self::Target,
861                    context: &mut $crate::WriteContext,
862                    ref_mode: $crate::RefMode,
863                    write_type_info: bool,
864                ) -> Result<(), $crate::Error> {
865                    let any = [<$trait_name ForyDispatch>]::checked_any(value.as_ref())?;
866                    if ref_mode != $crate::RefMode::None
867                        && context
868                            .ref_writer
869                            .try_write_arc_ref(&mut context.writer, value)
870                    {
871                        return Ok(());
872                    }
873                    [<$trait_name ForyDispatch>]::write_checked(
874                        any,
875                        context,
876                        write_type_info,
877                    )
878                }
879
880                #[inline(always)]
881                fn read(
882                    context: &mut $crate::ReadContext,
883                    ref_mode: $crate::RefMode,
884                    read_type_info: bool,
885                ) -> Result<Self::Target, $crate::Error> {
886                    let ref_flag = if ref_mode != $crate::RefMode::None {
887                        context.ref_reader.read_ref_flag(&mut context.reader)?
888                    } else {
889                        $crate::RefFlag::NotNullValue
890                    };
891                    match ref_flag {
892                        $crate::RefFlag::Null => {
893                            Err([<$trait_name ForyDispatch>]::null_arc_value())
894                        }
895                        $crate::RefFlag::Ref => {
896                            let ref_id =
897                                context.ref_reader.read_ref_id(&mut context.reader)?;
898                            context
899                                .ref_reader
900                                .get_arc_ref::<dyn $trait_name>(ref_id)
901                                .ok_or_else(|| {
902                                    [<$trait_name ForyDispatch>]::missing_ref(ref_id)
903                                })
904                        }
905                        $crate::RefFlag::NotNullValue => {
906                            context.inc_depth()?;
907                            let result = (|| {
908                                if !read_type_info {
909                                    return Err(
910                                        [<$trait_name ForyDispatch>]::missing_arc_metadata()
911                                    );
912                                }
913                                let type_info = context.read_any_type_info()?;
914                                [<$trait_name ForyDispatch>]::read_arc(context, &type_info)
915                            })();
916                            context.dec_depth();
917                            result
918                        }
919                        $crate::RefFlag::RefValue => {
920                            let ref_id = context.ref_reader.reserve_ref_id();
921                            context.inc_depth()?;
922                            let result = (|| {
923                                if !read_type_info {
924                                    return Err(
925                                        [<$trait_name ForyDispatch>]::missing_arc_metadata()
926                                    );
927                                }
928                                let type_info = context.read_any_type_info()?;
929                                [<$trait_name ForyDispatch>]::read_arc(context, &type_info)
930                            })();
931                            context.dec_depth();
932                            let value = result?;
933                            context.ref_reader.store_arc_ref_at(ref_id, value.clone());
934                            Ok(value)
935                        }
936                    }
937                }
938
939                #[inline(always)]
940                fn read_with_type_info(
941                    context: &mut $crate::ReadContext,
942                    ref_mode: $crate::RefMode,
943                    type_info: &std::rc::Rc<$crate::TypeInfo>,
944                ) -> Result<Self::Target, $crate::Error> {
945                    let ref_flag = if ref_mode != $crate::RefMode::None {
946                        context.ref_reader.read_ref_flag(&mut context.reader)?
947                    } else {
948                        $crate::RefFlag::NotNullValue
949                    };
950                    match ref_flag {
951                        $crate::RefFlag::Null => {
952                            Err([<$trait_name ForyDispatch>]::null_arc_value())
953                        }
954                        $crate::RefFlag::Ref => {
955                            let ref_id =
956                                context.ref_reader.read_ref_id(&mut context.reader)?;
957                            context
958                                .ref_reader
959                                .get_arc_ref::<dyn $trait_name>(ref_id)
960                                .ok_or_else(|| {
961                                    [<$trait_name ForyDispatch>]::missing_ref(ref_id)
962                                })
963                        }
964                        $crate::RefFlag::NotNullValue => {
965                            context.inc_depth()?;
966                            let result =
967                                [<$trait_name ForyDispatch>]::read_arc(context, type_info);
968                            context.dec_depth();
969                            result
970                        }
971                        $crate::RefFlag::RefValue => {
972                            let ref_id = context.ref_reader.reserve_ref_id();
973                            context.inc_depth()?;
974                            let result =
975                                [<$trait_name ForyDispatch>]::read_arc(context, type_info);
976                            context.dec_depth();
977                            let value = result?;
978                            context.ref_reader.store_arc_ref_at(ref_id, value.clone());
979                            Ok(value)
980                        }
981                    }
982                }
983
984                #[inline(always)]
985                fn write_type_info(
986                    _context: &mut $crate::WriteContext,
987                ) -> Result<(), $crate::Error> {
988                    Ok(())
989                }
990
991                #[inline(always)]
992                fn read_type_info(
993                    _context: &mut $crate::ReadContext,
994                ) -> Result<(), $crate::Error> {
995                    Ok(())
996                }
997
998                #[inline(always)]
999                fn static_type_id() -> $crate::TypeId {
1000                    $crate::TypeId::UNKNOWN
1001                }
1002
1003                #[inline(always)]
1004                fn reserved_space() -> usize {
1005                    $crate::type_id::SIZE_OF_REF_AND_TYPE
1006                }
1007
1008                const IS_POLYMORPHIC: bool = true;
1009
1010                const IS_SHARED_REF: bool = true;
1011
1012                const IS_WRAPPER: bool = true;
1013
1014                #[inline(always)]
1015                fn dynamic_type_id(
1016                    value: &Self::Target,
1017                ) -> Result<Option<std::any::TypeId>, $crate::Error> {
1018                    Ok(Some(
1019                        [<$trait_name ForyDispatch>]::any_ref(value.as_ref()).type_id(),
1020                    ))
1021                }
1022            }
1023
1024            $crate::register_trait_type!(
1025                @codec
1026                [$vis]
1027                [<$trait_name ArcCodec>],
1028                [<$trait_name ArcSerializer>],
1029                std::sync::Arc<dyn $trait_name>
1030            );
1031        }
1032    };
1033
1034    (@codec [$vis:vis] $codec:ident, $provider:ty, $target:ty) => {
1035        #[allow(dead_code)]
1036        #[doc(hidden)]
1037        $vis struct $codec<const NULLABLE: bool, const TRACK_REF: bool>;
1038
1039        impl<const NULLABLE: bool, const TRACK_REF: bool> $crate::Serializer
1040            for $codec<NULLABLE, TRACK_REF>
1041        {
1042            type Target = $target;
1043
1044            #[inline(always)]
1045            fn write_data(
1046                value: &Self::Target,
1047                context: &mut $crate::WriteContext,
1048            ) -> Result<(), $crate::Error> {
1049                <$provider as $crate::Serializer>::write_data(value, context)
1050            }
1051
1052            #[inline(always)]
1053            fn read_data(
1054                context: &mut $crate::ReadContext,
1055            ) -> Result<Self::Target, $crate::Error> {
1056                <$provider as $crate::Serializer>::read_data(context)
1057            }
1058
1059            #[inline(always)]
1060            fn default_value(
1061                context: &mut $crate::ReadContext,
1062            ) -> Result<Self::Target, $crate::Error> {
1063                <$provider as $crate::Serializer>::default_value(context)
1064            }
1065
1066            #[inline(always)]
1067            fn write(
1068                value: &Self::Target,
1069                context: &mut $crate::WriteContext,
1070                ref_mode: $crate::RefMode,
1071                write_type_info: bool,
1072            ) -> Result<(), $crate::Error> {
1073                <$provider as $crate::Serializer>::write(
1074                    value,
1075                    context,
1076                    ref_mode,
1077                    write_type_info,
1078                )
1079            }
1080
1081            #[inline(always)]
1082            fn write_type_info_value(
1083                context: &mut $crate::WriteContext,
1084                target_type_id: std::any::TypeId,
1085            ) -> Result<std::rc::Rc<$crate::TypeInfo>, $crate::Error> {
1086                <$provider as $crate::Serializer>::write_type_info_value(
1087                    context,
1088                    target_type_id,
1089                )
1090            }
1091
1092            #[inline(always)]
1093            fn write_with_type_info(
1094                value: &Self::Target,
1095                context: &mut $crate::WriteContext,
1096                ref_mode: $crate::RefMode,
1097                type_info: &std::rc::Rc<$crate::TypeInfo>,
1098            ) -> Result<(), $crate::Error> {
1099                <$provider as $crate::Serializer>::write_with_type_info(
1100                    value,
1101                    context,
1102                    ref_mode,
1103                    type_info,
1104                )
1105            }
1106
1107            #[inline(always)]
1108            fn read(
1109                context: &mut $crate::ReadContext,
1110                ref_mode: $crate::RefMode,
1111                read_type_info: bool,
1112            ) -> Result<Self::Target, $crate::Error> {
1113                <$provider as $crate::Serializer>::read(
1114                    context,
1115                    ref_mode,
1116                    read_type_info,
1117                )
1118            }
1119
1120            #[inline(always)]
1121            fn read_with_type_info(
1122                context: &mut $crate::ReadContext,
1123                ref_mode: $crate::RefMode,
1124                type_info: &std::rc::Rc<$crate::TypeInfo>,
1125            ) -> Result<Self::Target, $crate::Error> {
1126                <$provider as $crate::Serializer>::read_with_type_info(
1127                    context,
1128                    ref_mode,
1129                    type_info,
1130                )
1131            }
1132
1133            #[inline(always)]
1134            fn write_type_info(
1135                _context: &mut $crate::WriteContext,
1136            ) -> Result<(), $crate::Error> {
1137                Ok(())
1138            }
1139
1140            #[inline(always)]
1141            fn read_type_info(
1142                _context: &mut $crate::ReadContext,
1143            ) -> Result<(), $crate::Error> {
1144                Ok(())
1145            }
1146
1147            #[inline(always)]
1148            fn static_type_id() -> $crate::TypeId {
1149                $crate::TypeId::UNKNOWN
1150            }
1151
1152            #[inline(always)]
1153            fn reserved_space() -> usize {
1154                <$provider as $crate::Serializer>::reserved_space()
1155            }
1156
1157            const IS_OPTIONAL: bool = <$provider as $crate::Serializer>::IS_OPTIONAL;
1158
1159            const IS_POLYMORPHIC: bool = <$provider as $crate::Serializer>::IS_POLYMORPHIC;
1160
1161            const IS_SHARED_REF: bool = <$provider as $crate::Serializer>::IS_SHARED_REF;
1162
1163            const IS_WRAPPER: bool = <$provider as $crate::Serializer>::IS_WRAPPER;
1164
1165            const REQUIRES_SCOPED_ACCESS: bool =
1166                <$provider as $crate::Serializer>::REQUIRES_SCOPED_ACCESS;
1167
1168            #[inline(always)]
1169            fn dynamic_type_id(
1170                value: &Self::Target,
1171            ) -> Result<Option<std::any::TypeId>, $crate::Error> {
1172                <$provider as $crate::Serializer>::dynamic_type_id(value)
1173            }
1174
1175        }
1176
1177        impl<const NULLABLE: bool, const TRACK_REF: bool>
1178            $crate::serializer::codec::Codec<$target>
1179            for $codec<NULLABLE, TRACK_REF>
1180        {
1181            #[inline(always)]
1182            fn field_type(
1183                _type_resolver: &$crate::TypeResolver,
1184            ) -> Result<$crate::meta::FieldType, $crate::Error> {
1185                Ok($crate::meta::FieldType::new_with_ref(
1186                    $crate::TypeId::UNKNOWN as u32,
1187                    NULLABLE,
1188                    TRACK_REF,
1189                    Vec::new(),
1190                ))
1191            }
1192
1193            #[inline(always)]
1194            fn field_reserved_space() -> usize {
1195                <$provider as $crate::Serializer>::reserved_space()
1196                    + $crate::type_id::SIZE_OF_REF_AND_TYPE
1197            }
1198
1199            #[inline(always)]
1200            fn write_field(
1201                value: &$target,
1202                context: &mut $crate::WriteContext,
1203            ) -> Result<(), $crate::Error> {
1204                <$provider as $crate::Serializer>::write(
1205                    value,
1206                    context,
1207                    if TRACK_REF {
1208                        $crate::RefMode::Tracking
1209                    } else if NULLABLE {
1210                        $crate::RefMode::NullOnly
1211                    } else {
1212                        $crate::RefMode::None
1213                    },
1214                    true,
1215                )
1216            }
1217
1218            #[inline(always)]
1219            fn read_field(
1220                context: &mut $crate::ReadContext,
1221            ) -> Result<$target, $crate::Error> {
1222                <$provider as $crate::Serializer>::read(
1223                    context,
1224                    if TRACK_REF {
1225                        $crate::RefMode::Tracking
1226                    } else if NULLABLE {
1227                        $crate::RefMode::NullOnly
1228                    } else {
1229                        $crate::RefMode::None
1230                    },
1231                    true,
1232                )
1233            }
1234
1235            #[inline(always)]
1236            fn read_field_with_type(
1237                context: &mut $crate::ReadContext,
1238                remote_field_type: &$crate::meta::FieldType,
1239            ) -> Result<$target, $crate::Error> {
1240                <$provider as $crate::Serializer>::read(
1241                    context,
1242                    $crate::serializer::codec::field_ref_mode(remote_field_type),
1243                    true,
1244                )
1245            }
1246
1247            #[inline(always)]
1248            fn write_with_mode(
1249                value: &$target,
1250                context: &mut $crate::WriteContext,
1251                ref_mode: $crate::RefMode,
1252                write_type_info: bool,
1253                _has_generics: bool,
1254            ) -> Result<(), $crate::Error> {
1255                <$provider as $crate::Serializer>::write(
1256                    value,
1257                    context,
1258                    ref_mode,
1259                    write_type_info,
1260                )
1261            }
1262
1263            #[inline(always)]
1264            fn write_with_type_info(
1265                value: &$target,
1266                context: &mut $crate::WriteContext,
1267                ref_mode: $crate::RefMode,
1268                type_info: &std::rc::Rc<$crate::TypeInfo>,
1269                _has_generics: bool,
1270            ) -> Result<(), $crate::Error> {
1271                <$provider as $crate::Serializer>::write_with_type_info(
1272                    value,
1273                    context,
1274                    ref_mode,
1275                    type_info,
1276                )
1277            }
1278
1279            #[inline(always)]
1280            fn read_type_info_value(
1281                context: &mut $crate::ReadContext,
1282            ) -> Result<$crate::serializer::codec::CodecReadType, $crate::Error> {
1283                context
1284                    .read_any_type_info()
1285                    .map($crate::serializer::codec::CodecReadType::TypeInfo)
1286            }
1287        }
1288    };
1289}
1290
1291#[cfg(test)]
1292mod tests {
1293    use crate::{ForyObject, Serializer};
1294    use std::rc::Rc;
1295    use std::sync::Arc;
1296
1297    trait PrivateAnimal: ForyObject {}
1298
1299    struct PrivateDog;
1300
1301    impl PrivateAnimal for PrivateDog {}
1302
1303    register_trait_type!(PrivateAnimal, PrivateDog);
1304
1305    pub mod public_api {
1306        use crate::ForyObject;
1307
1308        pub trait PublicAnimal: ForyObject {}
1309
1310        pub struct PublicDog;
1311
1312        impl PublicAnimal for PublicDog {}
1313
1314        register_trait_type!(pub PublicAnimal, PublicDog);
1315
1316        pub trait SharedAnimal: ForyObject + Send + Sync {}
1317
1318        impl SharedAnimal for PublicDog {}
1319
1320        register_trait_type!(pub sync SharedAnimal, PublicDog);
1321    }
1322
1323    fn assert_target<S, T>()
1324    where
1325        S: Serializer<Target = T>,
1326        T: 'static,
1327    {
1328    }
1329
1330    #[test]
1331    fn trait_visibility_forms_compile() {
1332        assert_target::<PrivateAnimalRcSerializer, Rc<dyn PrivateAnimal>>();
1333        assert_target::<public_api::PublicAnimalRcSerializer, Rc<dyn public_api::PublicAnimal>>();
1334        assert_target::<public_api::SharedAnimalArcSerializer, Arc<dyn public_api::SharedAnimal>>();
1335    }
1336}