@@ -46,7 +46,7 @@ pub struct PyProjectToml {
4646 /// Tool-specific metadata.
4747 pub tool : Option < Tool > ,
4848 /// Non-project dependency groups, as defined in PEP 735.
49- pub dependency_groups : Option < BTreeMap < GroupName , Vec < DependencyGroupSpecifier > > > ,
49+ pub dependency_groups : Option < DependencyGroups > ,
5050 /// The raw unserialized document.
5151 #[ serde( skip) ]
5252 pub raw : String ,
@@ -540,6 +540,79 @@ impl Deref for SerdePattern {
540540 }
541541}
542542
543+ #[ derive( Debug , Clone , PartialEq ) ]
544+ #[ cfg_attr( test, derive( Serialize ) ) ]
545+ pub struct DependencyGroups ( BTreeMap < GroupName , Vec < DependencyGroupSpecifier > > ) ;
546+
547+ impl DependencyGroups {
548+ /// Returns the names of the dependency groups.
549+ pub fn keys ( & self ) -> impl Iterator < Item = & GroupName > {
550+ self . 0 . keys ( )
551+ }
552+
553+ /// Returns the dependency group with the given name.
554+ pub fn get ( & self , group : & GroupName ) -> Option < & Vec < DependencyGroupSpecifier > > {
555+ self . 0 . get ( group)
556+ }
557+
558+ /// Returns an iterator over the dependency groups.
559+ pub fn iter ( & self ) -> impl Iterator < Item = ( & GroupName , & Vec < DependencyGroupSpecifier > ) > {
560+ self . 0 . iter ( )
561+ }
562+ }
563+
564+ impl < ' a > IntoIterator for & ' a DependencyGroups {
565+ type Item = ( & ' a GroupName , & ' a Vec < DependencyGroupSpecifier > ) ;
566+ type IntoIter = std:: collections:: btree_map:: Iter < ' a , GroupName , Vec < DependencyGroupSpecifier > > ;
567+
568+ fn into_iter ( self ) -> Self :: IntoIter {
569+ self . 0 . iter ( )
570+ }
571+ }
572+
573+ /// Ensure that all keys in the TOML table are unique.
574+ impl < ' de > serde:: de:: Deserialize < ' de > for DependencyGroups {
575+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
576+ where
577+ D : Deserializer < ' de > ,
578+ {
579+ struct GroupVisitor ;
580+
581+ impl < ' de > serde:: de:: Visitor < ' de > for GroupVisitor {
582+ type Value = DependencyGroups ;
583+
584+ fn expecting ( & self , formatter : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
585+ formatter. write_str ( "a table with unique dependency group names" )
586+ }
587+
588+ fn visit_map < M > ( self , mut access : M ) -> Result < Self :: Value , M :: Error >
589+ where
590+ M : serde:: de:: MapAccess < ' de > ,
591+ {
592+ let mut sources = BTreeMap :: new ( ) ;
593+ while let Some ( ( key, value) ) =
594+ access. next_entry :: < GroupName , Vec < DependencyGroupSpecifier > > ( ) ?
595+ {
596+ match sources. entry ( key) {
597+ std:: collections:: btree_map:: Entry :: Occupied ( entry) => {
598+ return Err ( serde:: de:: Error :: custom ( format ! (
599+ "duplicate dependency group: `{}`" ,
600+ entry. key( )
601+ ) ) ) ;
602+ }
603+ std:: collections:: btree_map:: Entry :: Vacant ( entry) => {
604+ entry. insert ( value) ;
605+ }
606+ }
607+ }
608+ Ok ( DependencyGroups ( sources) )
609+ }
610+ }
611+
612+ deserializer. deserialize_map ( GroupVisitor )
613+ }
614+ }
615+
543616#[ derive( Serialize , Deserialize , Debug , Clone , PartialEq , Eq ) ]
544617#[ cfg_attr( feature = "schemars" , derive( schemars:: JsonSchema ) ) ]
545618#[ serde( rename_all = "kebab-case" , try_from = "SourcesWire" ) ]
0 commit comments