wasm_link/loading/
load_plugin_tree.rs1use std::sync::Arc ;
2use std::collections::HashMap ;
3use thiserror::Error ;
4use wasmtime::Engine;
5use wasmtime::component::Linker ;
6
7use crate::interface::{ InterfaceData, InterfaceCardinality };
8use crate::plugin::PluginData ;
9use crate::utils::PartialResult ;
10use super::{ load_socket, SocketState, LoadedSocket };
11
12
13
14#[derive( Error )]
23pub enum LoadError<I: InterfaceData, P: PluginData> {
24
25 #[error( "Invalid socket: {0}" )]
27 InvalidSocket( I::Id ),
28
29 #[error( "Loop detected loading: '{0}'" )]
31 LoopDetected( I::Id ),
32
33 #[error( "Failed to meet cardinality requirements: {0}, found {1}" )]
36 FailedCardinalityRequirements( InterfaceCardinality, usize ),
37
38 #[error( "Corrupted interface manifest: {0}" )]
40 CorruptedInterfaceManifest( I::Error ),
41
42 #[error( "Corrupted plugin manifest: {0}" )]
44 CorruptedPluginManifest( P::Error ),
45
46 #[error( "Failed to load component: {0}" )]
48 FailedToLoadComponent( wasmtime::Error ),
49
50 #[error( "Failed to read WASM data: {0}" )]
52 FailedToReadWasm( std::io::Error ),
53
54 #[error( "Failed to link root interface: {0}" )]
56 FailedToLinkInterface( wasmtime::Error ),
57
58 #[error( "Failed to link function '{0}': {1}" )]
60 FailedToLink( String, wasmtime::Error ),
61
62 #[error( "Handled failure" )]
64 AlreadyHandled,
65
66}
67
68impl<I: InterfaceData, P: PluginData> std::fmt::Debug for LoadError<I, P> {
69 fn fmt( &self, f: &mut std::fmt::Formatter<'_> ) -> std::fmt::Result {
70 match self {
71 Self::InvalidSocket( id ) => f.debug_tuple( "InvalidSocket" ).field( id ).finish(),
72 Self::LoopDetected( id ) => f.debug_tuple( "LoopDetected" ).field( id ).finish(),
73 Self::FailedCardinalityRequirements( c, n ) => f.debug_tuple( "FailedCardinalityRequirements" ).field( c ).field( n ).finish(),
74 Self::CorruptedInterfaceManifest( e ) => f.debug_tuple( "CorruptedInterfaceManifest" ).field( e ).finish(),
75 Self::CorruptedPluginManifest( e ) => f.debug_tuple( "CorruptedPluginManifest" ).field( e ).finish(),
76 Self::FailedToLoadComponent( e ) => f.debug_tuple( "FailedToLoadComponent" ).field( e ).finish(),
77 Self::FailedToReadWasm( e ) => f.debug_tuple( "FailedToReadWasm" ).field( e ).finish(),
78 Self::FailedToLinkInterface( e ) => f.debug_tuple( "FailedToLinkInterface" ).field( e ).finish(),
79 Self::FailedToLink( name, e ) => f.debug_tuple( "FailedToLink" ).field( name ).field( e ).finish(),
80 Self::AlreadyHandled => f.debug_struct( "AlreadyHandled" ).finish(),
81 }
82 }
83}
84
85pub(super) struct LoadResult<T, I: InterfaceData, P: PluginData + 'static> {
90 pub socket_map: HashMap<I::Id, SocketState<I, P>>,
91 pub result: Result<T, LoadError<I, P>>,
92 pub errors: Vec<LoadError<I, P>>,
93}
94
95#[allow( clippy::type_complexity )]
96#[inline] pub(crate) fn load_plugin_tree<I, P, InterfaceId>(
97 socket_map: HashMap<I::Id, ( I, Vec<P> )>,
98 engine: &Engine,
99 default_linker: &Linker<P>,
100 root: I::Id,
101) -> PartialResult<( Arc<I>, Arc<LoadedSocket<P, P::Id>> ), LoadError<I, P>, LoadError<I, P>>
102where
103 I: InterfaceData<Id = InterfaceId>,
104 P: PluginData<InterfaceId = InterfaceId>,
105 InterfaceId: Clone + std::hash::Hash + Eq,
106{
107 let socket_map = socket_map.into_iter()
108 .map(|( socket_id, ( interface, plugins ))| ( socket_id, SocketState::Unprocessed( interface, plugins )))
109 .collect();
110
111 match load_socket( socket_map, engine, default_linker, root ) {
112 LoadResult { socket_map: _, result: Ok(( interface, socket )), errors } => Ok((( interface, socket ), errors )),
113 LoadResult { socket_map: _, result: Err( err ), errors } => Err(( err, errors ))
114 }
115
116}