1- use std:: os:: raw:: c_char;
2-
31use anyhow:: { anyhow, Result } ;
42use cbor4ii:: core:: {
53 dec:: { self , Decode , Read } ,
@@ -73,7 +71,7 @@ fn cid_to_pydict<'py>(py: Python<'py>, cid: &Cid) -> Bound<'py, PyDict> {
7371 dict_obj
7472}
7573
76- fn map_key_cmp ( a : & str , b : & str ) -> std:: cmp:: Ordering {
74+ fn map_key_cmp ( a : & [ u8 ] , b : & [ u8 ] ) -> std:: cmp:: Ordering {
7775 /* The keys in every map must be sorted length-first by the byte representation of the string keys, where:
7876 - If two keys have different lengths, the shorter one sorts earlier;
7977 - If two keys have the same length, the one with the lower value in (byte-wise) lexical order sorts earlier.
@@ -136,17 +134,6 @@ fn get_bytes_from_py_any<'py>(obj: &'py Bound<'py, PyAny>) -> PyResult<&'py [u8]
136134 }
137135}
138136
139- fn string_new_bound < ' py > ( py : Python < ' py > , s : & str ) -> Result < Bound < ' py , PyString > > {
140- let ptr = s. as_ptr ( ) as * const c_char ;
141- let len = s. len ( ) as ffi:: Py_ssize_t ;
142- unsafe {
143- Ok (
144- Bound :: from_owned_ptr ( py, ffi:: PyUnicode_FromStringAndSize ( ptr, len) )
145- . cast_into_unchecked ( ) ,
146- )
147- }
148- }
149-
150137// Based on cbor4ii code.
151138fn peek_one < ' de , R : dec:: Read < ' de > > ( r : & mut R ) -> Result < u8 >
152139where
@@ -181,18 +168,20 @@ where
181168 let byte = peek_one ( r) ?;
182169 return Ok ( match dec:: if_major ( byte) {
183170 major:: UNSIGNED => u64:: decode ( r) ?. into_pyobject ( py) ?. into ( ) ,
184- major:: NEGATIVE => {
185- i128:: decode ( r) ?. into_pyobject ( py) ?. into ( )
186- }
171+ major:: NEGATIVE => i128:: decode ( r) ?. into_pyobject ( py) ?. into ( ) ,
187172 major:: BYTES => PyBytes :: new ( py, <types:: Bytes < & [ u8 ] > >:: decode ( r) ?. 0 )
188173 . into_pyobject ( py) ?
189174 . into ( ) ,
190- major:: STRING => string_new_bound (
191- py,
192- <& str >:: decode ( r) . map_err ( |_| anyhow ! ( "Invalid UTF-8 string" ) ) ?,
193- ) ?
194- . into_pyobject ( py) ?
195- . into ( ) ,
175+ major:: STRING => {
176+ // The UTF-8 validation is done when it's converted into a Python string
177+ PyString :: from_bytes (
178+ py,
179+ <types:: UncheckedStr < & [ u8 ] > >:: decode ( r)
180+ . map_err ( |_| anyhow ! ( "Cannot decode as bytes" ) ) ?
181+ . 0 ,
182+ ) ?
183+ . into ( )
184+ }
196185 major:: ARRAY => {
197186 let len: ffi:: Py_ssize_t =
198187 types:: Array :: len ( r) ?. expect ( "contains length" ) . try_into ( ) ?;
@@ -216,10 +205,13 @@ where
216205 let len = types:: Map :: len ( r) ?. expect ( "contains length" ) ;
217206 let dict = PyDict :: new ( py) ;
218207
219- let mut prev_key: Option < & str > = None ;
208+ let mut prev_key: Option < & [ u8 ] > = None ;
220209 for _ in 0 ..len {
221- // DAG-CBOR keys are always strings
222- let key = <& str >:: decode ( r) . map_err ( |_| anyhow ! ( "Map keys must be strings" ) ) ?;
210+ // DAG-CBOR keys are always strings. Python does the UTF-8 validation when creating
211+ // the string.
212+ let key = <types:: UncheckedStr < & [ u8 ] > >:: decode ( r)
213+ . map_err ( |_| anyhow ! ( "Map keys must be strings" ) ) ?
214+ . 0 ;
223215
224216 if let Some ( prev_key) = prev_key {
225217 // it cares about duplicated keys too thanks to Ordering::Equal
@@ -228,7 +220,7 @@ where
228220 }
229221 }
230222
231- let key_py = string_new_bound ( py, key) ? . into_pyobject ( py ) ?;
223+ let key_py = PyString :: from_bytes ( py, key) ?;
232224 prev_key = Some ( key) ;
233225
234226 let value_py = decode_dag_cbor_to_pyobject ( py, r, depth + 1 ) ?;
0 commit comments