@@ -3,7 +3,7 @@ use crate::{
3
3
Document , DocumentId , Error , Function , Interface , InterfaceId , Results , Type , TypeDef ,
4
4
TypeDefKind , TypeId , TypeOwner , UnresolvedPackage , World , WorldId , WorldItem ,
5
5
} ;
6
- use anyhow:: { bail, Context , Result } ;
6
+ use anyhow:: { anyhow , bail, Context , Result } ;
7
7
use id_arena:: { Arena , Id } ;
8
8
use indexmap:: { IndexMap , IndexSet } ;
9
9
use std:: collections:: { HashMap , HashSet } ;
@@ -376,6 +376,65 @@ impl Resolve {
376
376
. push ( interface. name . as_ref ( ) ?) ;
377
377
Some ( base. to_string ( ) )
378
378
}
379
+
380
+ /// Attempts to locate a default world for the `pkg` specified within this
381
+ /// [`Resolve`]. Optionally takes a string-based `world` "specifier" to
382
+ /// resolve the world.
383
+ ///
384
+ /// This is intended for use by bindings generators and such as the default
385
+ /// logic for locating a world within a package used for binding. The
386
+ /// `world` argument is typically a user-specified argument (which again is
387
+ /// optional and not required) where the `pkg` is determined ambiently by
388
+ /// the integration.
389
+ ///
390
+ /// If `world` is `None` (e.g. not specified by a user) then the package
391
+ /// must have exactly one `default world` within its documents, otherwise an
392
+ /// error will be returned. If `world` is `Some` then it's a `.`-separated
393
+ /// name where the first element is the name of the document and the second,
394
+ /// optional, element is the name of the `world`. For example the name `foo`
395
+ /// would mean the `default world` of the `foo` document. The name `foo.bar`
396
+ /// would mean the world named `bar` in the `foo` document.
397
+ pub fn select_world ( & self , pkg : PackageId , world : Option < & str > ) -> Result < WorldId > {
398
+ match world {
399
+ Some ( world) => {
400
+ let mut parts = world. splitn ( 2 , '.' ) ;
401
+ let doc = parts. next ( ) . unwrap ( ) ;
402
+ let world = parts. next ( ) ;
403
+ let doc = * self . packages [ pkg]
404
+ . documents
405
+ . get ( doc)
406
+ . ok_or_else ( || anyhow ! ( "no document named `{doc}` in package" ) ) ?;
407
+ match world {
408
+ Some ( name) => self . documents [ doc]
409
+ . worlds
410
+ . get ( name)
411
+ . copied ( )
412
+ . ok_or_else ( || anyhow ! ( "no world named `{name}` in document" ) ) ,
413
+ None => self . documents [ doc]
414
+ . default_world
415
+ . ok_or_else ( || anyhow ! ( "no default world in document" ) ) ,
416
+ }
417
+ }
418
+ None => {
419
+ if self . packages [ pkg] . documents . is_empty ( ) {
420
+ bail ! ( "no documents found in package" )
421
+ }
422
+
423
+ let mut unique_default_world = None ;
424
+ for ( _name, doc) in & self . documents {
425
+ if let Some ( default_world) = doc. default_world {
426
+ if unique_default_world. is_some ( ) {
427
+ bail ! ( "multiple default worlds found in package, one must be specified" )
428
+ } else {
429
+ unique_default_world = Some ( default_world) ;
430
+ }
431
+ }
432
+ }
433
+
434
+ unique_default_world. ok_or_else ( || anyhow ! ( "no default world in package" ) )
435
+ }
436
+ }
437
+ }
379
438
}
380
439
381
440
/// Structure returned by [`Resolve::merge`] which contains mappings from
0 commit comments