@@ -80,6 +80,28 @@ def convert(self, v: T.Any, ws_v: T.Any) -> object:
8080 return self .func (v if v is not None else ws_v )
8181
8282
83+ class DictMergeValue (ConvertValue ):
84+ """Merge the incoming array of tables with a dictionary;
85+ a user-provided function maps each table to one of the
86+ entries of the dictionary."""
87+
88+ def __init__ (self , func : T .Callable [[T .Any ], T .List [object ]], key : T .Callable [[T .Any ], str ], base : T .Mapping [str , object ] = None ) -> None :
89+ super ().__init__ (func , base )
90+ self .key = key
91+
92+ def convert (self , v : T .Any , ws_v : T .Any ) -> object :
93+ out = self .func (v if v is not None else ws_v )
94+ assert isinstance (out , list ) # for mypy
95+ assert isinstance (self .default , dict ) # for mypy
96+
97+ d = {self .key (x ): x for x in out }
98+ # FIXME: check how auto-discovered items are merged with Cargo.toml
99+ for k , v in self .default .items ():
100+ if k not in d :
101+ d [k ] = v
102+ return d
103+
104+
83105def _raw_to_dataclass (raw : T .Mapping [str , object ], cls : T .Type [_DI ], msg : str ,
84106 raw_from_workspace : T .Optional [T .Mapping [str , object ]] = None ,
85107 ignored_fields : T .Optional [T .List [str ]] = None ,
@@ -491,7 +513,7 @@ class Manifest:
491513 dev_dependencies : T .Dict [str , Dependency ] = dataclasses .field (default_factory = dict )
492514 build_dependencies : T .Dict [str , Dependency ] = dataclasses .field (default_factory = dict )
493515 lib : T .Optional [Library ] = None
494- bin : T .List [ Binary ] = dataclasses .field (default_factory = list )
516+ bin : T .Dict [ str , Binary ] = dataclasses .field (default_factory = dict )
495517 test : T .List [Test ] = dataclasses .field (default_factory = list )
496518 bench : T .List [Benchmark ] = dataclasses .field (default_factory = list )
497519 example : T .List [Example ] = dataclasses .field (default_factory = list )
@@ -516,6 +538,32 @@ def from_raw(cls, raw: raw.Manifest, path: str, workspace: T.Optional[Workspace]
516538 if pkg .autolib and os .path .exists (os .path .join (path , 'src/lib.rs' )):
517539 autolib = Library .from_raw ({}, pkg )
518540
541+ def _discover_targets (subdir : str ) -> T .Generator [T .Tuple [str , str ], None , None ]:
542+ """Discover .rs files in a subdirectory and yield (name, path) tuples."""
543+ target_dir = os .path .join (path , subdir )
544+ if os .path .isdir (target_dir ):
545+ for entry in os .listdir (target_dir ):
546+ if entry .endswith ('.rs' ):
547+ target_name = entry [:- 3 ] # Remove .rs extension
548+ yield target_name , f'{ subdir } /{ entry } '
549+
550+ autobins : T .Dict [str , Binary ] = {}
551+ if pkg .autobins :
552+ # Check for default binary (src/main.rs)
553+ if os .path .exists (os .path .join (path , 'src/main.rs' )):
554+ autobins [pkg .name ] = Binary .from_raw ({'name' : pkg .name , 'path' : 'src/main.rs' }, pkg )
555+ # Add additional binaries from src/bin/
556+ for bin_name , bin_path in _discover_targets ('src/bin' ):
557+ autobins [bin_name ] = Binary .from_raw ({'name' : bin_name , 'path' : bin_path }, pkg )
558+
559+ # Check for additional binaries in src/bin/
560+ bin_dir = os .path .join (path , 'src/bin' )
561+ if os .path .isdir (bin_dir ):
562+ for entry in os .listdir (bin_dir ):
563+ if entry .endswith ('.rs' ):
564+ bin_name = entry [:- 3 ] # Remove .rs extension
565+ autobins [bin_name ] = Binary .from_raw ({'name' : bin_name , 'path' : f'src/bin/{ entry } ' }, pkg )
566+
519567 def dependencies_from_raw (x : T .Dict [str , T .Any ]) -> T .Dict [str , Dependency ]:
520568 return {k : Dependency .from_raw (k , v , member_path , workspace ) for k , v in x .items ()}
521569
@@ -528,7 +576,9 @@ def dependencies_from_raw(x: T.Dict[str, T.Any]) -> T.Dict[str, Dependency]:
528576 build_dependencies = ConvertValue (dependencies_from_raw ),
529577 lints = ConvertValue (Lint .from_raw ),
530578 lib = ConvertValue (lambda x : Library .from_raw (x , pkg ), default = autolib ),
531- bin = ConvertValue (lambda x : [Binary .from_raw (b , pkg ) for b in x ]),
579+ bin = DictMergeValue (lambda x : [Binary .from_raw (b , pkg ) for b in x ],
580+ lambda x : x .name ,
581+ base = autobins ),
532582 test = ConvertValue (lambda x : [Test .from_raw (b , pkg ) for b in x ]),
533583 bench = ConvertValue (lambda x : [Benchmark .from_raw (b , pkg ) for b in x ]),
534584 example = ConvertValue (lambda x : [Example .from_raw (b , pkg ) for b in x ]),
0 commit comments