tvm_ffi/extra/
dispatch.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

//! Runtime type dispatch indexed by its tuple of arguments.

/// Runtime type dispatch with a complete handler outcome.
///
/// Implementations generated by `#[dispatch(prefix)]` use a borrowed receiver
/// (`&T` or `&mut T`) as `Self` and use `Ret = Option<R>`. Only the outer
/// `None` denotes no match: a matched error or inner `None` remains `Some(result)`
/// and does not try another handler. Consuming the receiver reference preserves
/// results borrowing it while ordinary method calls automatically borrow it.
/// The argument tuple and complete return type select an implementation.
#[diagnostic::on_unimplemented(
    message = "this receiver does not implement Dispatcher for the requested argument tuple",
    note = "use #[dispatch(prefix)] on typed handlers with compatible arguments and results"
)]
pub trait Dispatcher<Args, Ret> {
    fn dispatch_tuple(self, args: Args) -> Ret;
}

use crate::{error::Result, AnyView};

// Generated alias bounds must not make recovery depend on a temporary borrow.
#[doc(hidden)]
pub trait DispatchRecovery<S> {
    type Recovery;
}
impl<S, T: crate::type_traits::ContainerElement> DispatchRecovery<S> for T {
    type Recovery = ();
}
impl<'source, 'value> DispatchRecovery<crate::match_any_internal::ViewSource<'source>>
    for AnyView<'value>
{
    type Recovery = ();
}
impl<'source, 'value, T: crate::type_traits::ContainerElement>
    DispatchRecovery<crate::match_any_internal::CapabilitySource<'source>>
    for crate::MutationView<'value, T>
{
    type Recovery = crate::MutationView<'source>;
}

use super::structural_visit::{DefRegionKind, IntoWalker, NativeVisit, WalkResult};

// Borrowed traversal adapters forward this concrete tuple without making
// unknown-Args trait solving recurse through mutable reference layers.
impl<'receiver, 'inner, 'value, D, Ret> Dispatcher<(AnyView<'value>, DefRegionKind), Ret>
    for &'receiver mut &'inner mut D
where
    &'receiver mut D: Dispatcher<(AnyView<'value>, DefRegionKind), Ret>,
{
    #[inline(always)]
    fn dispatch_tuple(self, args: (AnyView<'value>, DefRegionKind)) -> Ret {
        <&'receiver mut D as Dispatcher<(AnyView<'value>, DefRegionKind), Ret>>::dispatch_tuple(
            &mut **self,
            args,
        )
    }
}

/// Dispatch for typed `structural_walk` observer callbacks.
///
/// This private engine bridge consumes the common normalized walk signature.
/// Matching is supplied by `Dispatcher`; its outer `None` means no match.
pub(crate) trait WalkDispatch: Sized {
    fn dispatch_walk(
        &mut self,
        value: AnyView<'_>,
        def_region_kind: DefRegionKind,
    ) -> Option<Result<WalkResult>>;
}

impl<V> WalkDispatch for V
where
    for<'receiver, 'value> &'receiver mut V:
        Dispatcher<(AnyView<'value>, DefRegionKind), Option<Result<WalkResult>>>,
{
    #[inline(always)]
    fn dispatch_walk(
        &mut self,
        value: AnyView<'_>,
        def_region_kind: DefRegionKind,
    ) -> Option<Result<WalkResult>> {
        self.dispatch_tuple((value, def_region_kind))
    }
}

#[doc(hidden)]
pub enum ByWalkDispatch {}

impl<'a, V: WalkDispatch> IntoWalker<ByWalkDispatch> for &'a mut V {
    type Walker = DispatchWalker<&'a mut V>;
    fn into_walker(self) -> Self::Walker {
        DispatchWalker { walker: self }
    }
}

/// Adapter from [`Dispatcher`](crate::Dispatcher) to the traversal's native callback.
#[doc(hidden)]
pub struct DispatchWalker<V> {
    walker: V,
}

impl<V> super::structural_visit::NativeContext for DispatchWalker<V> {}

impl<V: WalkDispatch> NativeVisit for DispatchWalker<&mut V> {
    fn visit(&mut self, value: AnyView<'_>, def_region_kind: DefRegionKind) -> Result<WalkResult> {
        self.walker
            .dispatch_walk(value, def_region_kind)
            .unwrap_or_else(|| Ok(WalkResult::Advance))
    }
}