@@ -855,20 +855,34 @@ fn sanitize_mpn_for_path(mpn: &str) -> String {
855855 }
856856}
857857
858- /// Sanitize a pin name to create a valid Starlark identifier
858+ /// Sanitize a pin name to create a valid Starlark identifier.
859+ /// Output follows UPPERCASE convention for io() parameters.
860+ ///
861+ /// Special handling:
862+ /// - `~` or `!` at start: becomes `N_` prefix (e.g., `~CS` → `N_CS`)
863+ /// - `+` at end: becomes `_POS` suffix (e.g., `V+` → `V_POS`)
864+ /// - `-` at end: becomes `_NEG` suffix (e.g., `V-` → `V_NEG`)
865+ /// - `+` or `-` elsewhere: becomes `_` (e.g., `A+B` → `A_B`)
866+ /// - `#`: becomes `H` (e.g., `CS#` → `CSH`)
867+ /// - All alphanumeric chars: uppercased
859868fn sanitize ( name : & str ) -> String {
860- let result = name
861- . chars ( )
862- . map ( |c| match c {
863- '+' => 'P' , // Plus becomes P (e.g., V+ → VP)
864- '-' => 'M' , // Minus becomes M (e.g., V- → VM)
865- '~' => 'n' , // Tilde (NOT) becomes n (e.g., ~CS → nCS)
866- '!' => 'n' , // Bang (NOT) also becomes n
867- '#' => 'h' , // Hash becomes h (e.g., CS# → CSh)
868- c if c. is_alphanumeric ( ) => c,
869- _ => '_' ,
870- } )
871- . collect :: < String > ( ) ;
869+ let chars: Vec < char > = name. chars ( ) . collect ( ) ;
870+ let len = chars. len ( ) ;
871+ let mut result = String :: with_capacity ( len + 8 ) ;
872+
873+ for ( i, & c) in chars. iter ( ) . enumerate ( ) {
874+ let is_last = i == len - 1 ;
875+
876+ match c {
877+ '+' if is_last => result. push_str ( "_POS" ) ,
878+ '-' if is_last => result. push_str ( "_NEG" ) ,
879+ '+' | '-' => result. push ( '_' ) ,
880+ '~' | '!' => result. push_str ( "N_" ) , // NOT prefix
881+ '#' => result. push ( 'H' ) ,
882+ c if c. is_alphanumeric ( ) => result. push ( c. to_ascii_uppercase ( ) ) ,
883+ _ => result. push ( '_' ) ,
884+ }
885+ }
872886
873887 // Remove consecutive underscores and trim underscores from start/end
874888 let sanitized = result
@@ -1835,4 +1849,71 @@ mod tests {
18351849
18361850 insta:: assert_snapshot!( result) ;
18371851 }
1852+
1853+ #[ test]
1854+ fn test_sanitize_pin_name_basic ( ) {
1855+ // Basic alphanumeric names get uppercased
1856+ assert_eq ! ( sanitize( "VCC" ) , "VCC" ) ;
1857+ assert_eq ! ( sanitize( "gnd" ) , "GND" ) ;
1858+ assert_eq ! ( sanitize( "GPIO1" ) , "GPIO1" ) ;
1859+ assert_eq ! ( sanitize( "sda" ) , "SDA" ) ;
1860+ }
1861+
1862+ #[ test]
1863+ fn test_sanitize_pin_name_plus_minus_at_end ( ) {
1864+ // + and - at end become _POS and _NEG
1865+ assert_eq ! ( sanitize( "V+" ) , "V_POS" ) ;
1866+ assert_eq ! ( sanitize( "V-" ) , "V_NEG" ) ;
1867+ assert_eq ! ( sanitize( "IN+" ) , "IN_POS" ) ;
1868+ assert_eq ! ( sanitize( "OUT-" ) , "OUT_NEG" ) ;
1869+ assert_eq ! ( sanitize( "VCC+" ) , "VCC_POS" ) ;
1870+ }
1871+
1872+ #[ test]
1873+ fn test_sanitize_pin_name_plus_minus_in_middle ( ) {
1874+ // + and - in middle become underscores
1875+ assert_eq ! ( sanitize( "A+B" ) , "A_B" ) ;
1876+ assert_eq ! ( sanitize( "IN-OUT" ) , "IN_OUT" ) ;
1877+ assert_eq ! ( sanitize( "V+REF" ) , "V_REF" ) ;
1878+ }
1879+
1880+ #[ test]
1881+ fn test_sanitize_pin_name_not_prefix ( ) {
1882+ // ~ and ! at start become N_ prefix
1883+ assert_eq ! ( sanitize( "~CS" ) , "N_CS" ) ;
1884+ assert_eq ! ( sanitize( "!RESET" ) , "N_RESET" ) ;
1885+ assert_eq ! ( sanitize( "~WR" ) , "N_WR" ) ;
1886+ assert_eq ! ( sanitize( "!OE" ) , "N_OE" ) ;
1887+ }
1888+
1889+ #[ test]
1890+ fn test_sanitize_pin_name_hash_suffix ( ) {
1891+ // # becomes H
1892+ assert_eq ! ( sanitize( "CS#" ) , "CSH" ) ;
1893+ assert_eq ! ( sanitize( "WE#" ) , "WEH" ) ;
1894+ }
1895+
1896+ #[ test]
1897+ fn test_sanitize_pin_name_special_chars ( ) {
1898+ // Other special chars become underscores
1899+ assert_eq ! ( sanitize( "PIN/A" ) , "PIN_A" ) ;
1900+ assert_eq ! ( sanitize( "PIN.B" ) , "PIN_B" ) ;
1901+ assert_eq ! ( sanitize( "PIN A" ) , "PIN_A" ) ;
1902+ }
1903+
1904+ #[ test]
1905+ fn test_sanitize_pin_name_leading_digit ( ) {
1906+ // Leading digit gets P prefix
1907+ assert_eq ! ( sanitize( "1" ) , "P1" ) ;
1908+ assert_eq ! ( sanitize( "1A" ) , "P1A" ) ;
1909+ assert_eq ! ( sanitize( "123" ) , "P123" ) ;
1910+ }
1911+
1912+ #[ test]
1913+ fn test_sanitize_pin_name_consecutive_underscores ( ) {
1914+ // Consecutive underscores get collapsed
1915+ assert_eq ! ( sanitize( "A__B" ) , "A_B" ) ;
1916+ assert_eq ! ( sanitize( "A___B" ) , "A_B" ) ;
1917+ assert_eq ! ( sanitize( "_A_" ) , "A" ) ;
1918+ }
18381919}
0 commit comments