@@ -84,26 +84,67 @@ impl SpecificFilterType {
8484 }
8585}
8686
87- /// Encodes permission bits in the last byte of a script string
88- /// Returns the script with permission byte prepended
87+ /// Encodes permission bits in the last 2 ascii chars of a script string
88+ /// Returns the script with permission appended
8989pub ( crate ) fn encode_script_with_permission (
9090 mut script : String ,
9191 permission : PermissionMask ,
9292) -> String {
93- script. push ( permission. to_bits ( ) as char ) ;
93+ const HEX_CHARS : & [ u8 ; 16 ] = b"0123456789abcdef" ;
94+ let high = ( permission. to_bits ( ) >> 4 ) as usize ;
95+ let low = ( permission. to_bits ( ) & 0x0f ) as usize ;
96+
97+ script. push ( HEX_CHARS [ high] as char ) ;
98+ script. push ( HEX_CHARS [ low] as char ) ;
9499 script
95100}
96101
97- /// Decodes permission bits from the last byte of a script string
102+ /// Decodes permission bits from the last 2 ascii chars of a script string
98103/// Returns (permission, script) tuple
99104pub ( crate ) fn decode_script_with_permission ( encoded_script : & str ) -> ( PermissionMask , & str ) {
100- if encoded_script. is_empty ( ) {
101- return ( PermissionMask :: default ( ) , encoded_script) ;
105+ if encoded_script. len ( ) < 2 {
106+ return ( PermissionMask :: default ( ) , "" ) ;
107+ }
108+ let mut last_chars = encoded_script. char_indices ( ) . rev ( ) ;
109+ // unwrap: length >= 2 asserted above
110+ let ( digit2, digit1) = ( last_chars. next ( ) . unwrap ( ) , last_chars. next ( ) . unwrap ( ) ) ;
111+ fn parse_hex ( c : char ) -> Option < u8 > {
112+ match c {
113+ '0' ..='9' => Some ( c as u8 - b'0' ) ,
114+ 'a' ..='f' => Some ( c as u8 - b'a' + 10 ) ,
115+ _ => None ,
116+ }
102117 }
118+ if let ( Some ( d1) , Some ( d2) ) = ( parse_hex ( digit1. 1 ) , parse_hex ( digit2. 1 ) ) {
119+ let permission = PermissionMask :: from_bits ( d1 << 4 | d2) ;
120+ ( permission, & encoded_script[ ..digit1. 0 ] )
121+ } else {
122+ ( PermissionMask :: default ( ) , "" )
123+ }
124+ }
125+
126+ #[ cfg( test) ]
127+ mod tests {
128+ use super :: * ;
103129
104- let last_char = encoded_script. chars ( ) . last ( ) . unwrap ( ) ;
105- let permission_bits = last_char as u8 ;
106- let permission = PermissionMask :: from_bits ( permission_bits) ;
107- let script = & encoded_script[ ..encoded_script. len ( ) - 1 ] ;
108- ( permission, script)
130+ #[ test]
131+ fn test_encode_decode_script_with_permission ( ) {
132+ for permission in 0u8 ..=255u8 {
133+ let script = "console.log('测试 🚀 emoji')" . to_string ( ) ;
134+ let permission = PermissionMask :: from_bits ( permission) ;
135+
136+ let encoded = encode_script_with_permission ( script. clone ( ) , permission) ;
137+ let ( decoded_permission, decoded_script) = decode_script_with_permission ( & encoded) ;
138+
139+ assert_eq ! ( decoded_permission. to_bits( ) , permission. to_bits( ) ) ;
140+ assert_eq ! ( decoded_script, script) ;
141+ }
142+ }
143+
144+ #[ test]
145+ fn test_encode_decode_script_with_permission_empty ( ) {
146+ let ( permission, script) = decode_script_with_permission ( "" ) ;
147+ assert_eq ! ( permission. to_bits( ) , 0 ) ;
148+ assert_eq ! ( script, "" ) ;
149+ }
109150}
0 commit comments