1
1
use std:: borrow:: Cow ;
2
2
use std:: fmt:: Debug ;
3
+ use std:: io:: { self , Write } ;
3
4
4
5
use pyo3:: exceptions:: PyTypeError ;
5
6
use pyo3:: prelude:: * ;
@@ -9,7 +10,7 @@ use pyo3::{intern, PyTraverseError, PyVisit};
9
10
10
11
use enum_dispatch:: enum_dispatch;
11
12
use serde:: Serialize ;
12
- use serde_json:: ser:: PrettyFormatter ;
13
+ use serde_json:: ser:: { Formatter , PrettyFormatter } ;
13
14
14
15
use crate :: build_tools:: py_schema_err;
15
16
use crate :: build_tools:: py_schema_error_type;
@@ -349,6 +350,70 @@ impl Serialize for PydanticSerializer<'_> {
349
350
}
350
351
}
351
352
353
+ struct EscapeNonAsciiFormatter ;
354
+
355
+ impl Formatter for EscapeNonAsciiFormatter {
356
+ fn write_string_fragment < W : ?Sized + Write > ( & mut self , writer : & mut W , fragment : & str ) -> io:: Result < ( ) > {
357
+ for ch in fragment. chars ( ) {
358
+ if ch. is_ascii ( ) {
359
+ writer. write_all ( ch. encode_utf8 ( & mut [ 0 ; 4 ] ) . as_bytes ( ) ) ?;
360
+ } else {
361
+ for escape in ch. encode_utf16 ( & mut [ 0 ; 2 ] ) {
362
+ write ! ( writer, "\\ u{escape:04x}" ) ?;
363
+ }
364
+ }
365
+ }
366
+ Ok ( ( ) )
367
+ }
368
+ }
369
+
370
+ struct EscapeNonAsciiPrettyFormatter < ' a > {
371
+ pretty : PrettyFormatter < ' a > ,
372
+ escape_non_ascii : EscapeNonAsciiFormatter ,
373
+ }
374
+
375
+ impl < ' a > EscapeNonAsciiPrettyFormatter < ' a > {
376
+ pub fn with_indent ( indent : & ' a [ u8 ] ) -> Self {
377
+ Self {
378
+ pretty : PrettyFormatter :: with_indent ( indent) ,
379
+ escape_non_ascii : EscapeNonAsciiFormatter ,
380
+ }
381
+ }
382
+ }
383
+
384
+ macro_rules! defer {
385
+ ( $formatter: ident, $fun: ident) => {
386
+ fn $fun<W >( & mut self , writer: & mut W ) -> io:: Result <( ) >
387
+ where
388
+ W : ?Sized + io:: Write ,
389
+ {
390
+ self . $formatter. $fun( writer)
391
+ }
392
+ } ;
393
+ ( $formatter: ident, $fun: ident, $val: ty) => {
394
+ fn $fun<W >( & mut self , writer: & mut W , val: $val) -> io:: Result <( ) >
395
+ where
396
+ W : ?Sized + io:: Write ,
397
+ {
398
+ self . $formatter. $fun( writer, val)
399
+ }
400
+ } ;
401
+ }
402
+
403
+ impl < ' a > Formatter for EscapeNonAsciiPrettyFormatter < ' a > {
404
+ defer ! ( escape_non_ascii, write_string_fragment, & str ) ;
405
+ defer ! ( pretty, begin_array) ;
406
+ defer ! ( pretty, end_array) ;
407
+ defer ! ( pretty, begin_array_value, bool ) ;
408
+ defer ! ( pretty, end_array_value) ;
409
+ defer ! ( pretty, begin_object) ;
410
+ defer ! ( pretty, end_object) ;
411
+ defer ! ( pretty, begin_object_key, bool ) ;
412
+ defer ! ( pretty, end_object_key) ;
413
+ defer ! ( pretty, begin_object_value) ;
414
+ defer ! ( pretty, end_object_value) ;
415
+ }
416
+
352
417
#[ allow( clippy:: too_many_arguments) ]
353
418
pub ( crate ) fn to_json_bytes (
354
419
value : & Bound < ' _ , PyAny > ,
@@ -357,25 +422,40 @@ pub(crate) fn to_json_bytes(
357
422
exclude : Option < & Bound < ' _ , PyAny > > ,
358
423
extra : & Extra ,
359
424
indent : Option < usize > ,
425
+ ensure_ascii : bool ,
360
426
expected_json_size : usize ,
361
427
) -> PyResult < Vec < u8 > > {
362
428
let serializer = PydanticSerializer :: new ( value, serializer, include, exclude, extra) ;
363
429
364
430
let writer: Vec < u8 > = Vec :: with_capacity ( expected_json_size) ;
365
- let bytes = match indent {
366
- Some ( indent) => {
431
+
432
+ let bytes = match ( indent, ensure_ascii) {
433
+ ( Some ( indent) , true ) => {
434
+ let indent = vec ! [ b' ' ; indent] ;
435
+ let formatter = EscapeNonAsciiPrettyFormatter :: with_indent ( & indent) ;
436
+ let mut ser = PythonSerializer :: with_formatter ( writer, formatter) ;
437
+ serializer. serialize ( & mut ser) . map_err ( se_err_py_err) ?;
438
+ ser. into_inner ( )
439
+ }
440
+ ( Some ( indent) , false ) => {
367
441
let indent = vec ! [ b' ' ; indent] ;
368
442
let formatter = PrettyFormatter :: with_indent ( & indent) ;
369
443
let mut ser = PythonSerializer :: with_formatter ( writer, formatter) ;
370
444
serializer. serialize ( & mut ser) . map_err ( se_err_py_err) ?;
371
445
ser. into_inner ( )
372
446
}
373
- None => {
447
+ ( None , true ) => {
448
+ let mut ser = PythonSerializer :: with_formatter ( writer, EscapeNonAsciiFormatter ) ;
449
+ serializer. serialize ( & mut ser) . map_err ( se_err_py_err) ?;
450
+ ser. into_inner ( )
451
+ }
452
+ ( None , false ) => {
374
453
let mut ser = PythonSerializer :: new ( writer) ;
375
454
serializer. serialize ( & mut ser) . map_err ( se_err_py_err) ?;
376
455
ser. into_inner ( )
377
456
}
378
457
} ;
458
+
379
459
Ok ( bytes)
380
460
}
381
461
0 commit comments