11use anyhow:: Context ;
22use indexmap:: IndexMap ;
33use semver:: Version ;
4- use spin_app:: locked:: { self , InheritConfiguration , LockedComponent , LockedComponentDependency } ;
4+ use spin_app:: locked:: InheritConfiguration as LockedInheritConfiguration ;
55use spin_serde:: { DependencyName , KebabId } ;
66use std:: collections:: BTreeMap ;
77use thiserror:: Error ;
@@ -28,18 +28,68 @@ use wac_graph::{CompositionGraph, NodeId};
2828/// composition graph into a byte array and return it.
2929pub async fn compose < ' a , L : ComponentSourceLoader > (
3030 loader : & ' a L ,
31- component : & LockedComponent ,
31+ component : & L :: Component ,
3232) -> Result < Vec < u8 > , ComposeError > {
3333 Composer :: new ( loader) . compose ( component) . await
3434}
3535
36+ #[ async_trait:: async_trait]
37+ pub trait DependencyLike {
38+ fn inherit ( & self ) -> InheritConfiguration ;
39+ fn export ( & self ) -> & Option < String > ;
40+ }
41+
42+ pub enum InheritConfiguration {
43+ All ,
44+ Some ( Vec < String > ) ,
45+ }
46+
47+ #[ async_trait:: async_trait]
48+ pub trait ComponentLike {
49+ type Dependency : DependencyLike ;
50+
51+ fn dependencies (
52+ & self ,
53+ ) -> impl std:: iter:: ExactSizeIterator < Item = ( & DependencyName , & Self :: Dependency ) > ;
54+ fn id ( & self ) -> & str ;
55+ }
56+
57+ #[ async_trait:: async_trait]
58+ impl ComponentLike for spin_app:: locked:: LockedComponent {
59+ type Dependency = spin_app:: locked:: LockedComponentDependency ;
60+
61+ fn dependencies (
62+ & self ,
63+ ) -> impl std:: iter:: ExactSizeIterator < Item = ( & DependencyName , & Self :: Dependency ) > {
64+ self . dependencies . iter ( )
65+ }
66+
67+ fn id ( & self ) -> & str {
68+ & self . id
69+ }
70+ }
71+
72+ #[ async_trait:: async_trait]
73+ impl DependencyLike for spin_app:: locked:: LockedComponentDependency {
74+ fn inherit ( & self ) -> InheritConfiguration {
75+ match & self . inherit {
76+ LockedInheritConfiguration :: All => InheritConfiguration :: All ,
77+ LockedInheritConfiguration :: Some ( cfgs) => InheritConfiguration :: Some ( cfgs. clone ( ) ) ,
78+ }
79+ }
80+
81+ fn export ( & self ) -> & Option < String > {
82+ & self . export
83+ }
84+ }
85+
3686/// This trait is used to load component source code from a locked component source across various embdeddings.
3787#[ async_trait:: async_trait]
3888pub trait ComponentSourceLoader {
39- async fn load_component_source (
40- & self ,
41- source : & locked :: LockedComponentSource ,
42- ) -> anyhow:: Result < Vec < u8 > > ;
89+ type Component : ComponentLike < Dependency = Self :: Dependency > ;
90+ type Dependency : DependencyLike ;
91+ async fn load_component_source ( & self , source : & Self :: Component ) -> anyhow :: Result < Vec < u8 > > ;
92+ async fn load_dependency_source ( & self , source : & Self :: Dependency ) -> anyhow:: Result < Vec < u8 > > ;
4393}
4494
4595/// Represents an error that can occur when composing dependencies.
@@ -98,19 +148,19 @@ struct Composer<'a, L> {
98148}
99149
100150impl < ' a , L : ComponentSourceLoader > Composer < ' a , L > {
101- async fn compose ( mut self , component : & LockedComponent ) -> Result < Vec < u8 > , ComposeError > {
151+ async fn compose ( mut self , component : & L :: Component ) -> Result < Vec < u8 > , ComposeError > {
102152 let source = self
103153 . loader
104- . load_component_source ( & component. source )
154+ . load_component_source ( component)
105155 . await
106156 . map_err ( ComposeError :: PrepareError ) ?;
107157
108- if component. dependencies . is_empty ( ) {
158+ if component. dependencies ( ) . len ( ) == 0 {
109159 return Ok ( source) ;
110160 }
111161
112162 let ( world_id, instantiation_id) = self
113- . register_package ( & component. id , None , source)
163+ . register_package ( component. id ( ) , None , source)
114164 . map_err ( ComposeError :: PrepareError ) ?;
115165
116166 let prepared = self . prepare_dependencies ( world_id, component) . await ?;
@@ -150,15 +200,15 @@ impl<'a, L: ComponentSourceLoader> Composer<'a, L> {
150200 async fn prepare_dependencies (
151201 & mut self ,
152202 world_id : WorldId ,
153- component : & LockedComponent ,
203+ component : & L :: Component ,
154204 ) -> Result < IndexMap < String , DependencyInfo > , ComposeError > {
155205 let imports = self . graph . types ( ) [ world_id] . imports . clone ( ) ;
156206
157207 let import_keys = imports. keys ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
158208
159209 let mut mappings: BTreeMap < String , Vec < DependencyInfo > > = BTreeMap :: new ( ) ;
160210
161- for ( dependency_name, dependency) in & component. dependencies {
211+ for ( dependency_name, dependency) in component. dependencies ( ) {
162212 let mut matched = Vec :: new ( ) ;
163213
164214 for import_name in & import_keys {
@@ -171,7 +221,7 @@ impl<'a, L: ComponentSourceLoader> Composer<'a, L> {
171221
172222 if matched. is_empty ( ) {
173223 return Err ( ComposeError :: UnmatchedDependencyName {
174- component_id : component. id . clone ( ) ,
224+ component_id : component. id ( ) . to_owned ( ) ,
175225 dependency_name : dependency_name. clone ( ) ,
176226 } ) ;
177227 }
@@ -195,7 +245,7 @@ impl<'a, L: ComponentSourceLoader> Composer<'a, L> {
195245
196246 if !conflicts. is_empty ( ) {
197247 return Err ( ComposeError :: DependencyConflicts {
198- component_id : component. id . clone ( ) ,
248+ component_id : component. id ( ) . to_owned ( ) ,
199249 conflicts : conflicts
200250 . into_iter ( )
201251 . map ( |( import_name, infos) | {
@@ -300,19 +350,16 @@ impl<'a, L: ComponentSourceLoader> Composer<'a, L> {
300350 async fn register_dependency (
301351 & mut self ,
302352 dependency_name : DependencyName ,
303- dependency : & LockedComponentDependency ,
353+ dependency : & L :: Dependency ,
304354 ) -> anyhow:: Result < DependencyInfo > {
305- let mut dependency_source = self
306- . loader
307- . load_component_source ( & dependency. source )
308- . await ?;
355+ let mut dependency_source = self . loader . load_dependency_source ( dependency) . await ?;
309356
310357 let package_name = match & dependency_name {
311358 DependencyName :: Package ( name) => name. package . to_string ( ) ,
312359 DependencyName :: Plain ( name) => name. to_string ( ) ,
313360 } ;
314361
315- match & dependency. inherit {
362+ match dependency. inherit ( ) {
316363 InheritConfiguration :: Some ( configurations) => {
317364 if configurations. is_empty ( ) {
318365 // Configuration inheritance is disabled, apply deny_all adapter
@@ -333,7 +380,7 @@ impl<'a, L: ComponentSourceLoader> Composer<'a, L> {
333380 manifest_name : dependency_name,
334381 instantiation_id,
335382 world_id,
336- export_name : dependency. export . clone ( ) ,
383+ export_name : dependency. export ( ) . clone ( ) ,
337384 } )
338385 }
339386
0 commit comments