22//! constructing Python strings using Rust's `fmt::Write` trait.
33//! It allows for incremental string construction, without the need for repeated allocations, and
44//! is particularly useful for building strings in a performance-sensitive context.
5- use crate :: ffi:: compat:: {
6- PyUnicodeWriter_Create , PyUnicodeWriter_Discard , PyUnicodeWriter_Finish ,
7- PyUnicodeWriter_WriteChar , PyUnicodeWriter_WriteUTF8 ,
5+ #[ cfg( not( Py_LIMITED_API ) ) ]
6+ use {
7+ crate :: ffi:: compat:: {
8+ PyUnicodeWriter_Create , PyUnicodeWriter_Discard , PyUnicodeWriter_Finish ,
9+ PyUnicodeWriter_WriteChar , PyUnicodeWriter_WriteUTF8 ,
10+ } ,
11+ crate :: ffi_ptr_ext:: FfiPtrExt ,
12+ crate :: impl_:: callback:: WrappingCastTo ,
13+ crate :: types:: { PyAnyMethods , PyString } ,
14+ crate :: { ffi, Bound , PyErr , PyResult , Python } ,
15+ std:: ptr:: NonNull ,
16+ std:: { fmt, mem} ,
817} ;
9- use crate :: ffi_ptr_ext:: FfiPtrExt ;
10- use crate :: impl_:: callback:: WrappingCastTo ;
11- use crate :: types:: { PyAnyMethods , PyString } ;
12- use crate :: { ffi, Bound , PyErr , PyResult , Python } ;
13- use std:: ptr:: NonNull ;
14- use std:: { fmt, mem} ;
1518
19+ /// This is like the `format!` macro, but it returns a `PyString` instead of a `String`.
20+ #[ macro_export]
21+ macro_rules! py_format {
22+ ( $py: expr, $( $arg: tt) * ) => {
23+ $crate:: types:: PyString :: from_fmt( $py, format_args!( $( $arg) * ) )
24+ }
25+ }
26+
27+ #[ cfg( not( Py_LIMITED_API ) ) ]
1628/// The `PyUnicodeWriter` is a utility for efficiently constructing Python strings
1729pub struct PyUnicodeWriter {
1830 writer : NonNull < ffi:: PyUnicodeWriter > ,
1931 last_error : Option < PyErr > ,
2032}
2133
34+ #[ cfg( not( Py_LIMITED_API ) ) ]
2235impl PyUnicodeWriter {
2336 /// Creates a new `PyUnicodeWriter`.
2437 pub fn new ( py : Python < ' _ > ) -> PyResult < Self > {
@@ -63,6 +76,7 @@ impl PyUnicodeWriter {
6376 }
6477}
6578
79+ #[ cfg( not( Py_LIMITED_API ) ) ]
6680impl fmt:: Write for PyUnicodeWriter {
6781 fn write_str ( & mut self , s : & str ) -> fmt:: Result {
6882 let result = unsafe {
@@ -87,6 +101,7 @@ impl fmt::Write for PyUnicodeWriter {
87101 }
88102}
89103
104+ #[ cfg( not( Py_LIMITED_API ) ) ]
90105impl Drop for PyUnicodeWriter {
91106 fn drop ( & mut self ) {
92107 unsafe {
@@ -97,13 +112,15 @@ impl Drop for PyUnicodeWriter {
97112
98113#[ cfg( test) ]
99114mod tests {
115+ #[ cfg( not( Py_LIMITED_API ) ) ]
100116 use super :: * ;
101117 use crate :: types:: PyStringMethods ;
102118 use crate :: { IntoPyObject , Python } ;
103- use std:: fmt:: Write ;
104119
105120 #[ test]
121+ #[ cfg( not( Py_LIMITED_API ) ) ]
106122 fn unicode_writer_test ( ) {
123+ use std:: fmt:: Write ;
107124 Python :: with_gil ( |py| {
108125 let mut writer = PyUnicodeWriter :: new ( py) . unwrap ( ) ;
109126 write ! ( writer, "Hello {}!" , "world" ) . unwrap ( ) ;
@@ -116,19 +133,15 @@ mod tests {
116133 #[ test]
117134 fn test_pystring_from_fmt ( ) {
118135 Python :: with_gil ( |py| {
119- PyString :: from_fmt ( py, format_args ! ( "Hello {}!" , "world" ) ) . unwrap ( ) ;
136+ py_format ! ( py, "Hello {}!" , "world" ) . unwrap ( ) ;
120137 } ) ;
121138 }
122139
123140 #[ test]
124141 fn test_complex_format ( ) {
125142 Python :: with_gil ( |py| {
126143 let complex_value = ( 42 , "foo" , 3.14 ) . into_pyobject ( py) . unwrap ( ) ;
127- let py_string = PyString :: from_fmt (
128- py,
129- format_args ! ( "This is some complex value: {complex_value}" ) ,
130- )
131- . unwrap ( ) ;
144+ let py_string = py_format ! ( py, "This is some complex value: {complex_value}" ) . unwrap ( ) ;
132145 let actual = py_string. to_cow ( ) . unwrap ( ) ;
133146 let expected = "This is some complex value: (42, 'foo', 3.14)" ;
134147 assert_eq ! ( actual, expected) ;
0 commit comments