Use with_gil instead of acquire_gil in examples
This commit is contained in:
parent
3fa10a38d3
commit
aedd6352e3
|
@ -85,25 +85,25 @@ struct MyClass {
|
|||
num: i32,
|
||||
debug: bool,
|
||||
}
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let obj = PyCell::new(py, MyClass { num: 3, debug: true }).unwrap();
|
||||
{
|
||||
let obj_ref = obj.borrow(); // Get PyRef
|
||||
assert_eq!(obj_ref.num, 3);
|
||||
// You cannot get PyRefMut unless all PyRefs are dropped
|
||||
assert!(obj.try_borrow_mut().is_err());
|
||||
}
|
||||
{
|
||||
let mut obj_mut = obj.borrow_mut(); // Get PyRefMut
|
||||
obj_mut.num = 5;
|
||||
// You cannot get any other refs until the PyRefMut is dropped
|
||||
assert!(obj.try_borrow().is_err());
|
||||
assert!(obj.try_borrow_mut().is_err());
|
||||
}
|
||||
Python::with_gil(|py| {
|
||||
let obj = PyCell::new(py, MyClass { num: 3, debug: true }).unwrap();
|
||||
{
|
||||
let obj_ref = obj.borrow(); // Get PyRef
|
||||
assert_eq!(obj_ref.num, 3);
|
||||
// You cannot get PyRefMut unless all PyRefs are dropped
|
||||
assert!(obj.try_borrow_mut().is_err());
|
||||
}
|
||||
{
|
||||
let mut obj_mut = obj.borrow_mut(); // Get PyRefMut
|
||||
obj_mut.num = 5;
|
||||
// You cannot get any other refs until the PyRefMut is dropped
|
||||
assert!(obj.try_borrow().is_err());
|
||||
assert!(obj.try_borrow_mut().is_err());
|
||||
}
|
||||
|
||||
// You can convert `&PyCell` to a Python object
|
||||
pyo3::py_run!(py, obj, "assert obj.num == 5")
|
||||
// You can convert `&PyCell` to a Python object
|
||||
pyo3::py_run!(py, obj, "assert obj.num == 5");
|
||||
});
|
||||
```
|
||||
|
||||
`&PyCell<T>` is bounded by the same lifetime as a [`GILGuard`].
|
||||
|
@ -118,15 +118,14 @@ struct MyClass {
|
|||
num: i32,
|
||||
}
|
||||
fn return_myclass() -> Py<MyClass> {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
Py::new(py, MyClass { num: 1 }).unwrap()
|
||||
Python::with_gil(|py| Py::new(py, MyClass { num: 1 }).unwrap())
|
||||
}
|
||||
let gil = Python::acquire_gil();
|
||||
let obj = return_myclass();
|
||||
let cell = obj.as_ref(gil.python()); // Py<MyClass>::as_ref returns &PyCell<MyClass>
|
||||
let obj_ref = cell.borrow(); // Get PyRef<T>
|
||||
assert_eq!(obj_ref.num, 1);
|
||||
Python::with_gil(|py|{
|
||||
let cell = obj.as_ref(py); // Py<MyClass>::as_ref returns &PyCell<MyClass>
|
||||
let obj_ref = cell.borrow(); // Get PyRef<T>
|
||||
assert_eq!(obj_ref.num, 1);
|
||||
});
|
||||
```
|
||||
|
||||
## Customizing the class
|
||||
|
@ -261,10 +260,10 @@ impl SubSubClass {
|
|||
SubClass::method2(super_).map(|x| x * v)
|
||||
}
|
||||
}
|
||||
# let gil = Python::acquire_gil();
|
||||
# let py = gil.python();
|
||||
# let subsub = pyo3::PyCell::new(py, SubSubClass::new()).unwrap();
|
||||
# pyo3::py_run!(py, subsub, "assert subsub.method3() == 3000")
|
||||
# Python::with_gil(|py| {
|
||||
# let subsub = pyo3::PyCell::new(py, SubSubClass::new()).unwrap();
|
||||
# pyo3::py_run!(py, subsub, "assert subsub.method3() == 3000")
|
||||
# });
|
||||
```
|
||||
|
||||
You can also inherit native types such as `PyDict`, if they implement
|
||||
|
@ -274,8 +273,7 @@ However, because of some technical problems, we don't currently provide safe upc
|
|||
that inherit native types. Even in such cases, you can unsafely get a base class by raw pointer conversion.
|
||||
|
||||
```rust
|
||||
# #[cfg(Py_LIMITED_API)] fn main() {}
|
||||
# #[cfg(not(Py_LIMITED_API))] fn main() {
|
||||
# #[cfg(not(Py_LIMITED_API))] {
|
||||
# use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
use pyo3::{AsPyPointer, PyNativeType};
|
||||
|
@ -300,10 +298,10 @@ impl DictWithCounter {
|
|||
dict.set_item(key, value)
|
||||
}
|
||||
}
|
||||
# let gil = Python::acquire_gil();
|
||||
# let py = gil.python();
|
||||
# let cnt = pyo3::PyCell::new(py, DictWithCounter::new()).unwrap();
|
||||
# pyo3::py_run!(py, cnt, "cnt.set('abc', 10); assert cnt['abc'] == 10")
|
||||
# Python::with_gil(|py| {
|
||||
# let cnt = pyo3::PyCell::new(py, DictWithCounter::new()).unwrap();
|
||||
# pyo3::py_run!(py, cnt, "cnt.set('abc', 10); assert cnt['abc'] == 10")
|
||||
# });
|
||||
# }
|
||||
```
|
||||
|
||||
|
@ -563,10 +561,10 @@ impl MyClass {
|
|||
}
|
||||
}
|
||||
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let my_class = py.get_type::<MyClass>();
|
||||
pyo3::py_run!(py, my_class, "assert my_class.my_attribute == 'hello'")
|
||||
Python::with_gil(|py| {
|
||||
let my_class = py.get_type::<MyClass>();
|
||||
pyo3::py_run!(py, my_class, "assert my_class.my_attribute == 'hello'")
|
||||
});
|
||||
```
|
||||
|
||||
Note that unlike class variables defined in Python code, class attributes defined in Rust cannot
|
||||
|
@ -712,8 +710,7 @@ This simple technique works for the case when there is zero or one implementatio
|
|||
The `#[pyclass]` macro expands to roughly the code seen below. The `PyClassImplCollector` is the type used internally by PyO3 for dtolnay specialization:
|
||||
|
||||
```rust
|
||||
# #[cfg(not(feature = "multiple-pymethods"))]
|
||||
# {
|
||||
# #[cfg(not(feature = "multiple-pymethods"))] {
|
||||
# use pyo3::prelude::*;
|
||||
// Note: the implementation differs slightly with the `multiple-pymethods` feature enabled.
|
||||
|
||||
|
@ -808,10 +805,10 @@ impl pyo3::class::impl_::PyClassImpl for MyClass {
|
|||
collector.buffer_procs()
|
||||
}
|
||||
}
|
||||
# let gil = Python::acquire_gil();
|
||||
# let py = gil.python();
|
||||
# let cls = py.get_type::<MyClass>();
|
||||
# pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'")
|
||||
# Python::with_gil(|py| {
|
||||
# let cls = py.get_type::<MyClass>();
|
||||
# pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'")
|
||||
# });
|
||||
# }
|
||||
```
|
||||
|
||||
|
|
|
@ -275,17 +275,12 @@ impl PyIterProtocol for Container {
|
|||
}
|
||||
}
|
||||
|
||||
# let gil = Python::acquire_gil();
|
||||
# let py = gil.python();
|
||||
# let inst = pyo3::PyCell::new(
|
||||
# py,
|
||||
# Container {
|
||||
# iter: vec![1, 2, 3, 4],
|
||||
# },
|
||||
# )
|
||||
# .unwrap();
|
||||
# pyo3::py_run!(py, inst, "assert list(inst) == [1, 2, 3, 4]");
|
||||
# pyo3::py_run!(py, inst, "assert list(iter(iter(inst))) == [1, 2, 3, 4]");
|
||||
# Python::with_gil(|py| {
|
||||
# let container = Container { iter: vec![1, 2, 3, 4] };
|
||||
# let inst = pyo3::PyCell::new(py, container).unwrap();
|
||||
# pyo3::py_run!(py, inst, "assert list(inst) == [1, 2, 3, 4]");
|
||||
# pyo3::py_run!(py, inst, "assert list(iter(iter(inst))) == [1, 2, 3, 4]");
|
||||
# });
|
||||
```
|
||||
|
||||
For more details on Python's iteration protocols, check out [the "Iterator Types" section of the library
|
||||
|
|
|
@ -23,14 +23,11 @@ use pyo3::exceptions::PyException;
|
|||
|
||||
create_exception!(mymodule, CustomError, PyException);
|
||||
|
||||
fn main() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
Python::with_gil(|py| {
|
||||
let ctx = [("CustomError", py.get_type::<CustomError>())].into_py_dict(py);
|
||||
|
||||
py.run("assert str(CustomError) == \"<class 'mymodule.CustomError'>\"", None, Some(&ctx)).unwrap();
|
||||
py.run("assert CustomError('oops').args == ('oops',)", None, Some(&ctx)).unwrap();
|
||||
}
|
||||
pyo3::py_run!(py, *ctx, "assert str(CustomError) == \"<class 'mymodule.CustomError'>\"");
|
||||
pyo3::py_run!(py, *ctx, "assert CustomError('oops').args == ('oops',)");
|
||||
});
|
||||
```
|
||||
|
||||
When using PyO3 to create an extension module, you can add the new exception to
|
||||
|
@ -58,13 +55,11 @@ To raise an exception, first you need to obtain an exception type and construct
|
|||
use pyo3::{Python, PyErr};
|
||||
use pyo3::exceptions::PyTypeError;
|
||||
|
||||
fn main() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
Python::with_gil(|py| {
|
||||
PyTypeError::new_err("Error").restore(py);
|
||||
assert!(PyErr::occurred(py));
|
||||
drop(PyErr::fetch(py));
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
From `pyfunction`s and `pyclass` methods, returning an `Err(PyErr)` is enough;
|
||||
|
@ -103,14 +98,12 @@ In PyO3 every native type has access to the [`PyAny::is_instance`] method which
|
|||
use pyo3::Python;
|
||||
use pyo3::types::{PyBool, PyList};
|
||||
|
||||
fn main() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
Python::with_gil(|py| {
|
||||
assert!(PyBool::new(py, true).is_instance::<PyBool>().unwrap());
|
||||
let list = PyList::new(py, &[1, 2, 3, 4]);
|
||||
assert!(!list.is_instance::<PyBool>().unwrap());
|
||||
assert!(list.is_instance::<PyList>().unwrap());
|
||||
}
|
||||
});
|
||||
```
|
||||
[`PyAny::is_instance`] calls the underlying [`PyType::is_instance`](https://docs.rs/pyo3/latest/pyo3/types/struct.PyType.html#method.is_instance)
|
||||
method to do the actual work.
|
||||
|
@ -120,10 +113,10 @@ To check the type of an exception, you can similarly do:
|
|||
```rust
|
||||
# use pyo3::exceptions::PyTypeError;
|
||||
# use pyo3::prelude::*;
|
||||
# let gil = Python::acquire_gil();
|
||||
# let py = gil.python();
|
||||
# Python::with_gil(|py| {
|
||||
# let err = PyTypeError::new_err(());
|
||||
err.is_instance::<PyTypeError>(py);
|
||||
# });
|
||||
```
|
||||
|
||||
## Handling Rust errors
|
||||
|
|
|
@ -266,22 +266,16 @@ To migrate, just pass a `py` argument to any calls to these methods.
|
|||
|
||||
Before:
|
||||
```rust,compile_fail
|
||||
use pyo3::prelude::*;
|
||||
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
# pyo3::Python::with_gil(|py| {
|
||||
py.None().get_refcnt();
|
||||
# })
|
||||
```
|
||||
|
||||
After:
|
||||
```rust
|
||||
use pyo3::prelude::*;
|
||||
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
# pyo3::Python::with_gil(|py| {
|
||||
py.None().get_refcnt(py);
|
||||
# })
|
||||
```
|
||||
|
||||
## from 0.9.* to 0.10
|
||||
|
@ -296,18 +290,20 @@ Before:
|
|||
```rust,compile_fail
|
||||
use pyo3::ObjectProtocol;
|
||||
|
||||
let gil = pyo3::Python::acquire_gil();
|
||||
let obj = gil.python().eval("lambda: 'Hi :)'", None, None).unwrap();
|
||||
# pyo3::Python::with_gil(|py| {
|
||||
let obj = py.eval("lambda: 'Hi :)'", None, None).unwrap();
|
||||
let hi: &pyo3::types::PyString = obj.call0().unwrap().downcast().unwrap();
|
||||
assert_eq!(hi.len().unwrap(), 5);
|
||||
# })
|
||||
```
|
||||
|
||||
After:
|
||||
```rust
|
||||
let gil = pyo3::Python::acquire_gil();
|
||||
let obj = gil.python().eval("lambda: 'Hi :)'", None, None).unwrap();
|
||||
# pyo3::Python::with_gil(|py| {
|
||||
let obj = py.eval("lambda: 'Hi :)'", None, None).unwrap();
|
||||
let hi: &pyo3::types::PyString = obj.call0().unwrap().downcast().unwrap();
|
||||
assert_eq!(hi.len().unwrap(), 5);
|
||||
# })
|
||||
```
|
||||
|
||||
### No `#![feature(specialization)]` in user code
|
||||
|
@ -380,16 +376,16 @@ impl Names {
|
|||
self.names.append(&mut other.names)
|
||||
}
|
||||
}
|
||||
# let gil = Python::acquire_gil();
|
||||
# let py = gil.python();
|
||||
# let names = PyCell::new(py, Names::new()).unwrap();
|
||||
# pyo3::py_run!(py, names, r"
|
||||
# try:
|
||||
# names.merge(names)
|
||||
# assert False, 'Unreachable'
|
||||
# except RuntimeError as e:
|
||||
# assert str(e) == 'Already borrowed'
|
||||
# ");
|
||||
# Python::with_gil(|py| {
|
||||
# let names = PyCell::new(py, Names::new()).unwrap();
|
||||
# pyo3::py_run!(py, names, r"
|
||||
# try:
|
||||
# names.merge(names)
|
||||
# assert False, 'Unreachable'
|
||||
# except RuntimeError as e:
|
||||
# assert str(e) == 'Already borrowed'
|
||||
# ");
|
||||
# })
|
||||
```
|
||||
`Names` has a `merge` method, which takes `&mut self` and another argument of type `&mut Self`.
|
||||
Given this `#[pyclass]`, calling `names.merge(names)` in Python raises
|
||||
|
@ -410,9 +406,9 @@ Before:
|
|||
# use pyo3::prelude::*;
|
||||
# #[pyclass]
|
||||
# struct MyClass {}
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
# Python::with_gil(|py| {
|
||||
let obj_ref = PyRef::new(py, MyClass {}).unwrap();
|
||||
# })
|
||||
```
|
||||
|
||||
After:
|
||||
|
@ -420,10 +416,10 @@ After:
|
|||
# use pyo3::prelude::*;
|
||||
# #[pyclass]
|
||||
# struct MyClass {}
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
# Python::with_gil(|py| {
|
||||
let obj = PyCell::new(py, MyClass {}).unwrap();
|
||||
let obj_ref = obj.borrow();
|
||||
# })
|
||||
```
|
||||
|
||||
#### Object extraction
|
||||
|
@ -445,8 +441,7 @@ After:
|
|||
# use pyo3::types::IntoPyDict;
|
||||
# #[pyclass] #[derive(Clone)] struct MyClass {}
|
||||
# #[pymethods] impl MyClass { #[new]fn new() -> Self { MyClass {} }}
|
||||
# let gil = Python::acquire_gil();
|
||||
# let py = gil.python();
|
||||
# Python::with_gil(|py| {
|
||||
# let typeobj = py.get_type::<MyClass>();
|
||||
# let d = [("c", typeobj)].into_py_dict(py);
|
||||
# let create_obj = || py.eval("c()", None, Some(d)).unwrap();
|
||||
|
@ -458,6 +453,7 @@ let obj_cloned: MyClass = obj.extract().unwrap(); // extracted by cloning the ob
|
|||
// we need to drop obj_ref before we can extract a PyRefMut due to Rust's rules of references
|
||||
}
|
||||
let obj_ref_mut: PyRefMut<MyClass> = obj.extract().unwrap();
|
||||
# })
|
||||
```
|
||||
|
||||
|
||||
|
|
|
@ -38,21 +38,20 @@ fn main() {
|
|||
let arg2 = "arg2";
|
||||
let arg3 = "arg3";
|
||||
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
Python::with_gil(|py| {
|
||||
let obj = SomeObject::new(py);
|
||||
|
||||
let obj = SomeObject::new(py);
|
||||
// call object without empty arguments
|
||||
obj.call0(py);
|
||||
|
||||
// call object without empty arguments
|
||||
obj.call0(py);
|
||||
// call object with PyTuple
|
||||
let args = PyTuple::new(py, &[arg1, arg2, arg3]);
|
||||
obj.call1(py, args);
|
||||
|
||||
// call object with PyTuple
|
||||
let args = PyTuple::new(py, &[arg1, arg2, arg3]);
|
||||
obj.call1(py, args);
|
||||
|
||||
// pass arguments as rust tuple
|
||||
let args = (arg1, arg2, arg3);
|
||||
obj.call1(py, args);
|
||||
// pass arguments as rust tuple
|
||||
let args = (arg1, arg2, arg3);
|
||||
obj.call1(py, args);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -79,23 +78,22 @@ fn main() {
|
|||
let key2 = "key2";
|
||||
let val2 = 2;
|
||||
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
Python::with_gil(|py| {
|
||||
let obj = SomeObject::new(py);
|
||||
|
||||
let obj = SomeObject::new(py);
|
||||
// call object with PyDict
|
||||
let kwargs = [(key1, val1)].into_py_dict(py);
|
||||
obj.call(py, (), Some(kwargs));
|
||||
|
||||
// call object with PyDict
|
||||
let kwargs = [(key1, val1)].into_py_dict(py);
|
||||
obj.call(py, (), Some(kwargs));
|
||||
// pass arguments as Vec
|
||||
let kwargs = vec![(key1, val1), (key2, val2)];
|
||||
obj.call(py, (), Some(kwargs.into_py_dict(py)));
|
||||
|
||||
// pass arguments as Vec
|
||||
let kwargs = vec![(key1, val1), (key2, val2)];
|
||||
obj.call(py, (), Some(kwargs.into_py_dict(py)));
|
||||
|
||||
// pass arguments as HashMap
|
||||
let mut kwargs = HashMap::<&str, i32>::new();
|
||||
kwargs.insert(key1, 1);
|
||||
obj.call(py, (), Some(kwargs.into_py_dict(py)));
|
||||
// pass arguments as HashMap
|
||||
let mut kwargs = HashMap::<&str, i32>::new();
|
||||
kwargs.insert(key1, 1);
|
||||
obj.call(py, (), Some(kwargs.into_py_dict(py)));
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -170,8 +170,7 @@ For a `Py<PyList>`, the conversions are as below:
|
|||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# use pyo3::types::PyList;
|
||||
# let gil = Python::acquire_gil();
|
||||
# let py = gil.python();
|
||||
# Python::with_gil(|py| {
|
||||
let list: Py<PyList> = PyList::empty(py).into();
|
||||
|
||||
// To &PyList with Py::as_ref() (borrows from the Py)
|
||||
|
@ -184,14 +183,14 @@ let _: &PyList = list.into_ref(py);
|
|||
# let list = list_clone;
|
||||
// To Py<PyAny> (aka PyObject) with .into()
|
||||
let _: Py<PyAny> = list.into();
|
||||
# })
|
||||
```
|
||||
|
||||
For a `#[pyclass] struct MyClass`, the conversions for `Py<MyClass>` are below:
|
||||
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# let gil = Python::acquire_gil();
|
||||
# let py = gil.python();
|
||||
# Python::with_gil(|py| {
|
||||
# #[pyclass] struct MyClass { }
|
||||
# Python::with_gil(|py| -> PyResult<()> {
|
||||
let my_class: Py<MyClass> = Py::new(py, MyClass { })?;
|
||||
|
@ -215,6 +214,7 @@ let _: PyRef<MyClass> = my_class.try_borrow(py)?;
|
|||
let _: PyRefMut<MyClass> = my_class.try_borrow_mut(py)?;
|
||||
# Ok(())
|
||||
# }).unwrap();
|
||||
# });
|
||||
```
|
||||
|
||||
### `PyCell<SomeType>`
|
||||
|
|
|
@ -38,11 +38,10 @@ use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, Python};
|
|||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # let gil = Python::acquire_gil();
|
||||
/// # let py = gil.python();
|
||||
/// # let inst = Py::new(py, Iter { count: 0 }).unwrap();
|
||||
/// # pyo3::py_run!(py, inst, "assert next(inst) == 1");
|
||||
/// # // test of StopIteration is done in examples/rustapi_module/pyclass_iter.rs
|
||||
/// # Python::with_gil(|py| {
|
||||
/// # let inst = Py::new(py, Iter { count: 0 }).unwrap();
|
||||
/// # pyo3::py_run!(py, inst, "assert next(inst) == 1");
|
||||
/// # }); // test of StopIteration is done in examples/rustapi_module/pyclass_iter.rs
|
||||
/// ```
|
||||
#[allow(unused_variables)]
|
||||
pub trait PyIterProtocol<'p>: PyClass {
|
||||
|
|
|
@ -18,10 +18,11 @@ use std::ptr::NonNull;
|
|||
///
|
||||
/// ```
|
||||
/// use pyo3::{AsPyPointer, prelude::*};
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let dict = pyo3::types::PyDict::new(gil.python());
|
||||
/// // All native object wrappers implement AsPyPointer!!!
|
||||
/// assert_ne!(dict.as_ptr(), std::ptr::null_mut());
|
||||
/// Python::with_gil(|py| {
|
||||
/// let dict = pyo3::types::PyDict::new(py);
|
||||
/// // All native object wrappers implement AsPyPointer!!!
|
||||
/// assert_ne!(dict.as_ptr(), std::ptr::null_mut());
|
||||
/// });
|
||||
/// ```
|
||||
pub trait AsPyPointer {
|
||||
/// Retrieves the underlying FFI pointer (as a borrowed pointer).
|
||||
|
|
|
@ -60,16 +60,10 @@ macro_rules! impl_exception_boilerplate {
|
|||
/// import_exception!(socket, gaierror);
|
||||
///
|
||||
/// fn main() {
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
///
|
||||
/// let ctx = [("gaierror", py.get_type::<gaierror>())].into_py_dict(py);
|
||||
/// py.run(
|
||||
/// "import socket; assert gaierror is socket.gaierror",
|
||||
/// None,
|
||||
/// Some(ctx),
|
||||
/// )
|
||||
/// .unwrap();
|
||||
/// Python::with_gil(|py| {
|
||||
/// let ctx = [("gaierror", py.get_type::<gaierror>())].into_py_dict(py);
|
||||
/// pyo3::py_run!(py, *ctx, "import socket; assert gaierror is socket.gaierror");
|
||||
/// });
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
|
@ -137,22 +131,17 @@ macro_rules! import_exception {
|
|||
/// create_exception!(mymodule, CustomError, PyException);
|
||||
///
|
||||
/// fn main() {
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
/// let error_type = py.get_type::<CustomError>();
|
||||
/// let ctx = [("CustomError", error_type)].into_py_dict(py);
|
||||
/// let type_description: String = py
|
||||
/// .eval("str(CustomError)", None, Some(&ctx))
|
||||
/// .unwrap()
|
||||
/// .extract()
|
||||
/// .unwrap();
|
||||
/// assert_eq!(type_description, "<class 'mymodule.CustomError'>");
|
||||
/// py.run(
|
||||
/// "assert CustomError('oops').args == ('oops',)",
|
||||
/// None,
|
||||
/// Some(ctx),
|
||||
/// )
|
||||
/// .unwrap();
|
||||
/// Python::with_gil(|py| {
|
||||
/// let error_type = py.get_type::<CustomError>();
|
||||
/// let ctx = [("CustomError", error_type)].into_py_dict(py);
|
||||
/// let type_description: String = py
|
||||
/// .eval("str(CustomError)", None, Some(&ctx))
|
||||
/// .unwrap()
|
||||
/// .extract()
|
||||
/// .unwrap();
|
||||
/// assert_eq!(type_description, "<class 'mymodule.CustomError'>");
|
||||
/// pyo3::py_run!(py, *ctx, "assert CustomError('oops').args == ('oops',)");
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
|
|
|
@ -178,8 +178,11 @@ where
|
|||
result
|
||||
}
|
||||
|
||||
/// RAII type that represents the Global Interpreter Lock acquisition. To get hold of a value of
|
||||
/// this type, see [`Python::acquire_gil`](struct.Python.html#method.acquire_gil).
|
||||
/// RAII type that represents the Global Interpreter Lock acquisition.
|
||||
///
|
||||
/// Users are strongly encouraged to [`Python::with_gil`](struct.Python.html#method.with_gil)
|
||||
/// instead of directly constructing this type.
|
||||
/// See [`Python::acquire_gil`](struct.Python.html#method.acquire_gil) for more.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
|
|
|
@ -286,6 +286,10 @@ macro_rules! wrap_pymodule {
|
|||
|
||||
/// A convenient macro to execute a Python code snippet, with some local variables set.
|
||||
///
|
||||
/// # Panics
|
||||
/// This macro internally calls [`Python::run`](struct.Python.html#method.run) and panics
|
||||
/// if it returns `Err`, after printing the error to stdout.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use pyo3::{prelude::*, py_run, types::PyList};
|
||||
|
@ -297,7 +301,6 @@ macro_rules! wrap_pymodule {
|
|||
///
|
||||
/// You can use this macro to test pyfunctions or pyclasses quickly.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use pyo3::{prelude::*, py_run, PyCell};
|
||||
/// #[pyclass]
|
||||
|
|
5
src/marshal.rs
Normal file → Executable file
5
src/marshal.rs
Normal file → Executable file
|
@ -21,15 +21,14 @@ pub const VERSION: i32 = 4;
|
|||
/// # Examples
|
||||
/// ```
|
||||
/// # use pyo3::{marshal, types::PyDict};
|
||||
/// # let gil = pyo3::Python::acquire_gil();
|
||||
/// # let py = gil.python();
|
||||
/// #
|
||||
/// # pyo3::Python::with_gil(|py| {
|
||||
/// let dict = PyDict::new(py);
|
||||
/// dict.set_item("aap", "noot").unwrap();
|
||||
/// dict.set_item("mies", "wim").unwrap();
|
||||
/// dict.set_item("zus", "jet").unwrap();
|
||||
///
|
||||
/// let bytes = marshal::dumps(py, dict, marshal::VERSION);
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn dumps<'a>(py: Python<'a>, object: &impl AsPyPointer, version: i32) -> PyResult<&'a PyBytes> {
|
||||
unsafe {
|
||||
|
|
|
@ -25,9 +25,7 @@ use std::cell::UnsafeCell;
|
|||
/// .get_or_init(py, || PyList::empty(py).into())
|
||||
/// .as_ref(py)
|
||||
/// }
|
||||
/// # let gil = Python::acquire_gil();
|
||||
/// # let py = gil.python();
|
||||
/// # assert_eq!(get_shared_list(py).len(), 0 );
|
||||
/// # Python::with_gil(|py| assert_eq!(get_shared_list(py).len(), 0));
|
||||
/// ```
|
||||
pub struct GILOnceCell<T>(UnsafeCell<Option<T>>);
|
||||
|
||||
|
|
|
@ -121,15 +121,15 @@ impl<T: PyClass> PyCellInner<T> {
|
|||
/// name: &'static str,
|
||||
/// author: &'static str,
|
||||
/// }
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
/// let book = Book {
|
||||
/// name: "The Man in the High Castle",
|
||||
/// author: "Philip Kindred Dick",
|
||||
/// };
|
||||
/// let book_cell = PyCell::new(py, book).unwrap();
|
||||
/// // you can expose PyCell to Python snippets
|
||||
/// pyo3::py_run!(py, book_cell, "assert book_cell.name[-6:] == 'Castle'");
|
||||
/// Python::with_gil(|py| {
|
||||
/// let book_cell = PyCell::new(py, book).unwrap();
|
||||
/// // `&PyCell` implements `ToPyObject`, so you can use it in a Python snippet
|
||||
/// pyo3::py_run!(py, book_cell, "assert book_cell.name[-6:] == 'Castle'");
|
||||
/// });
|
||||
/// ```
|
||||
/// You can use `slf: &PyCell<Self>` as an alternative `self` receiver of `#[pymethod]`,
|
||||
/// though you rarely need it.
|
||||
|
@ -154,10 +154,10 @@ impl<T: PyClass> PyCellInner<T> {
|
|||
/// Ok(*counter)
|
||||
/// }
|
||||
/// }
|
||||
/// # let gil = Python::acquire_gil();
|
||||
/// # let py = gil.python();
|
||||
/// # let counter = PyCell::new(py, Counter::default()).unwrap();
|
||||
/// # pyo3::py_run!(py, counter, "assert counter.increment('cat') == 1");
|
||||
/// # Python::with_gil(|py| {
|
||||
/// # let counter = PyCell::new(py, Counter::default()).unwrap();
|
||||
/// # pyo3::py_run!(py, counter, "assert counter.increment('cat') == 1");
|
||||
/// # });
|
||||
/// ```
|
||||
#[repr(C)]
|
||||
pub struct PyCell<T: PyClass> {
|
||||
|
@ -245,18 +245,18 @@ impl<T: PyClass> PyCell<T> {
|
|||
/// # use pyo3::prelude::*;
|
||||
/// #[pyclass]
|
||||
/// struct Class {}
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
/// let c = PyCell::new(py, Class {}).unwrap();
|
||||
/// {
|
||||
/// let m = c.borrow_mut();
|
||||
/// assert!(c.try_borrow().is_err());
|
||||
/// }
|
||||
/// Python::with_gil(|py| {
|
||||
/// let c = PyCell::new(py, Class {}).unwrap();
|
||||
/// {
|
||||
/// let m = c.borrow_mut();
|
||||
/// assert!(c.try_borrow().is_err());
|
||||
/// }
|
||||
///
|
||||
/// {
|
||||
/// let m = c.borrow();
|
||||
/// assert!(c.try_borrow().is_ok());
|
||||
/// }
|
||||
/// {
|
||||
/// let m = c.borrow();
|
||||
/// assert!(c.try_borrow().is_ok());
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
|
||||
self.thread_checker.ensure();
|
||||
|
@ -280,15 +280,15 @@ impl<T: PyClass> PyCell<T> {
|
|||
/// # use pyo3::prelude::*;
|
||||
/// #[pyclass]
|
||||
/// struct Class {}
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
/// let c = PyCell::new(py, Class {}).unwrap();
|
||||
/// {
|
||||
/// let m = c.borrow();
|
||||
/// assert!(c.try_borrow_mut().is_err());
|
||||
/// }
|
||||
/// Python::with_gil(|py| {
|
||||
/// let c = PyCell::new(py, Class {}).unwrap();
|
||||
/// {
|
||||
/// let m = c.borrow();
|
||||
/// assert!(c.try_borrow_mut().is_err());
|
||||
/// }
|
||||
///
|
||||
/// assert!(c.try_borrow_mut().is_ok());
|
||||
/// assert!(c.try_borrow_mut().is_ok());
|
||||
/// });
|
||||
/// ```
|
||||
pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError> {
|
||||
self.thread_checker.ensure();
|
||||
|
@ -315,19 +315,19 @@ impl<T: PyClass> PyCell<T> {
|
|||
/// # use pyo3::prelude::*;
|
||||
/// #[pyclass]
|
||||
/// struct Class {}
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
/// let c = PyCell::new(py, Class {}).unwrap();
|
||||
/// Python::with_gil(|py| {
|
||||
/// let c = PyCell::new(py, Class {}).unwrap();
|
||||
///
|
||||
/// {
|
||||
/// let m = c.borrow_mut();
|
||||
/// assert!(unsafe { c.try_borrow_unguarded() }.is_err());
|
||||
/// }
|
||||
/// {
|
||||
/// let m = c.borrow_mut();
|
||||
/// assert!(unsafe { c.try_borrow_unguarded() }.is_err());
|
||||
/// }
|
||||
///
|
||||
/// {
|
||||
/// let m = c.borrow();
|
||||
/// assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
|
||||
/// }
|
||||
/// {
|
||||
/// let m = c.borrow();
|
||||
/// assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
|
||||
self.thread_checker.ensure();
|
||||
|
@ -485,10 +485,10 @@ impl<T: PyClass + fmt::Debug> fmt::Debug for PyCell<T> {
|
|||
/// format!("{}(base: {}, cnt: {})", slf.name, basename, refcnt)
|
||||
/// }
|
||||
/// }
|
||||
/// # let gil = Python::acquire_gil();
|
||||
/// # let py = gil.python();
|
||||
/// # let sub = PyCell::new(py, Child::new()).unwrap();
|
||||
/// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 3)'");
|
||||
/// # Python::with_gil(|py| {
|
||||
/// # let sub = PyCell::new(py, Child::new()).unwrap();
|
||||
/// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 3)'");
|
||||
/// # });
|
||||
/// ```
|
||||
pub struct PyRef<'p, T: PyClass> {
|
||||
inner: &'p PyCellInner<T>,
|
||||
|
@ -549,10 +549,10 @@ where
|
|||
/// format!("{} {} {}", super_.as_ref().name1, super_.name2, subname)
|
||||
/// }
|
||||
/// }
|
||||
/// # let gil = Python::acquire_gil();
|
||||
/// # let py = gil.python();
|
||||
/// # let sub = PyCell::new(py, Sub::new()).unwrap();
|
||||
/// # pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'")
|
||||
/// # Python::with_gil(|py| {
|
||||
/// # let sub = PyCell::new(py, Sub::new()).unwrap();
|
||||
/// # pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'")
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn into_super(self) -> PyRef<'p, U> {
|
||||
let PyRef { inner } = self;
|
||||
|
|
|
@ -30,6 +30,7 @@ impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
|
|||
/// ```
|
||||
/// # use pyo3::prelude::*;
|
||||
/// # use pyo3::py_run;
|
||||
/// # use pyo3::types::IntoPyDict;
|
||||
/// #[pyclass(subclass)]
|
||||
/// struct BaseClass {
|
||||
/// #[pyo3(get)]
|
||||
|
@ -55,14 +56,18 @@ impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
|
|||
/// .add_subclass(SubSubClass { subsubname: "subsub" })
|
||||
/// }
|
||||
/// }
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
/// let typeobj = py.get_type::<SubSubClass>();
|
||||
/// let inst = typeobj.call((), None).unwrap();
|
||||
/// py_run!(py, inst, r#"
|
||||
/// assert inst.basename == 'base'
|
||||
/// assert inst.subname == 'sub'
|
||||
/// assert inst.subsubname == 'subsub'"#);
|
||||
/// Python::with_gil(|py| {
|
||||
/// let typeobj = py.get_type::<SubSubClass>();
|
||||
/// let sub_sub_class = typeobj.call((), None).unwrap();
|
||||
/// py_run!(
|
||||
/// py,
|
||||
/// sub_sub_class,
|
||||
/// r#"
|
||||
/// assert sub_sub_class.basename == 'base'
|
||||
/// assert sub_sub_class.subname == 'sub'
|
||||
/// assert sub_sub_class.subsubname == 'subsub'"#
|
||||
/// );
|
||||
/// });
|
||||
/// ```
|
||||
pub struct PyClassInitializer<T: PyClass> {
|
||||
init: T,
|
||||
|
|
|
@ -208,15 +208,16 @@ impl<'p> Python<'p> {
|
|||
/// Ok(sum)
|
||||
/// })
|
||||
/// }
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
/// let m = PyModule::new(py, "pcount").unwrap();
|
||||
/// m.add_function(wrap_pyfunction!(parallel_count, m).unwrap()).unwrap();
|
||||
/// let locals = [("pcount", m)].into_py_dict(py);
|
||||
/// py.run(r#"
|
||||
/// s = ["Flow", "my", "tears", "the", "Policeman", "Said"]
|
||||
/// assert pcount.parallel_count(s, "a") == 3
|
||||
/// "#, None, Some(locals));
|
||||
///
|
||||
/// Python::with_gil(|py| {
|
||||
/// let m = PyModule::new(py, "pcount").unwrap();
|
||||
/// m.add_function(wrap_pyfunction!(parallel_count, m).unwrap()).unwrap();
|
||||
/// let locals = [("pcount", m)].into_py_dict(py);
|
||||
/// pyo3::py_run!(py, *locals, r#"
|
||||
/// s = ["Flow", "my", "tears", "the", "Policeman", "Said"]
|
||||
/// assert pcount.parallel_count(s, "a") == 3
|
||||
/// "#);
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// **Note:**
|
||||
|
@ -280,11 +281,11 @@ impl<'p> Python<'p> {
|
|||
/// # Examples
|
||||
/// ```
|
||||
/// # use pyo3::{types::{PyBytes, PyDict}, prelude::*};
|
||||
/// # let gil = pyo3::Python::acquire_gil();
|
||||
/// # let py = gil.python();
|
||||
/// # Python::with_gil(|py| {
|
||||
/// let result = py.eval("[i * 10 for i in range(5)]", None, None).unwrap();
|
||||
/// let res: Vec<i64> = result.extract().unwrap();
|
||||
/// assert_eq!(res, vec![0, 10, 20, 30, 40])
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn eval(
|
||||
self,
|
||||
|
@ -303,22 +304,26 @@ impl<'p> Python<'p> {
|
|||
/// # Examples
|
||||
/// ```
|
||||
/// use pyo3::{types::{PyBytes, PyDict}, prelude::*};
|
||||
/// let gil = pyo3::Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
/// let locals = PyDict::new(py);
|
||||
/// py.run(
|
||||
/// r#"
|
||||
/// Python::with_gil(|py| {
|
||||
/// let locals = PyDict::new(py);
|
||||
/// py.run(
|
||||
/// r#"
|
||||
/// import base64
|
||||
/// s = 'Hello Rust!'
|
||||
/// ret = base64.b64encode(s.encode('utf-8'))
|
||||
/// "#,
|
||||
/// None,
|
||||
/// Some(locals),
|
||||
/// ).unwrap();
|
||||
/// let ret = locals.get_item("ret").unwrap();
|
||||
/// let b64: &PyBytes = ret.downcast().unwrap();
|
||||
/// assert_eq!(b64.as_bytes(), b"SGVsbG8gUnVzdCE=");
|
||||
/// None,
|
||||
/// Some(locals),
|
||||
/// )
|
||||
/// .unwrap();
|
||||
/// let ret = locals.get_item("ret").unwrap();
|
||||
/// let b64: &PyBytes = ret.downcast().unwrap();
|
||||
/// assert_eq!(b64.as_bytes(), b"SGVsbG8gUnVzdCE=");
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// You can use [`py_run!`](macro.py_run.html) for a handy alternative of `run`
|
||||
/// if you don't need `globals` and unwrapping is OK.
|
||||
pub fn run(
|
||||
self,
|
||||
code: &str,
|
||||
|
@ -602,21 +607,20 @@ impl<'p> Python<'p> {
|
|||
/// # Examples
|
||||
/// ```rust
|
||||
/// # use pyo3::prelude::*;
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
/// Python::with_gil(|py| {
|
||||
/// // Some long-running process like a webserver, which never releases the GIL.
|
||||
/// loop {
|
||||
/// // Create a new pool, so that PyO3 can clear memory at the end of the loop.
|
||||
/// let pool = unsafe { py.new_pool() };
|
||||
///
|
||||
/// // Some long-running process like a webserver, which never releases the GIL.
|
||||
/// loop {
|
||||
/// // Create a new pool, so that PyO3 can clear memory at the end of the loop.
|
||||
/// let pool = unsafe { py.new_pool() };
|
||||
/// // It is recommended to *always* immediately set py to the pool's Python, to help
|
||||
/// // avoid creating references with invalid lifetimes.
|
||||
/// let py = unsafe { pool.python() };
|
||||
///
|
||||
/// // It is recommended to *always* immediately set py to the pool's Python, to help
|
||||
/// // avoid creating references with invalid lifetimes.
|
||||
/// let py = unsafe { pool.python() };
|
||||
///
|
||||
/// // do stuff...
|
||||
/// # break; // Exit the loop so that doctest terminates!
|
||||
/// }
|
||||
/// // do stuff...
|
||||
/// # break; // Exit the loop so that doctest terminates!
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// # Safety
|
||||
|
|
|
@ -28,12 +28,13 @@ use std::os::raw::c_int;
|
|||
/// ```
|
||||
/// use pyo3::prelude::*;
|
||||
/// use pyo3::types::{PyAny, PyDict, PyList};
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let dict = PyDict::new(gil.python());
|
||||
/// assert!(dict.is_instance::<PyAny>().unwrap());
|
||||
/// let any: &PyAny = dict.as_ref();
|
||||
/// assert!(any.downcast::<PyDict>().is_ok());
|
||||
/// assert!(any.downcast::<PyList>().is_err());
|
||||
/// Python::with_gil(|py| {
|
||||
/// let dict = PyDict::new(py);
|
||||
/// assert!(dict.is_instance::<PyAny>().unwrap());
|
||||
/// let any: &PyAny = dict.as_ref();
|
||||
/// assert!(any.downcast::<PyDict>().is_ok());
|
||||
/// assert!(any.downcast::<PyList>().is_err());
|
||||
/// });
|
||||
/// ```
|
||||
#[repr(transparent)]
|
||||
pub struct PyAny(UnsafeCell<ffi::PyObject>);
|
||||
|
@ -255,16 +256,16 @@ impl PyAny {
|
|||
/// # use pyo3::prelude::*;
|
||||
/// use pyo3::types::IntoPyDict;
|
||||
///
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
/// let list = vec![3, 6, 5, 4, 7].to_object(py);
|
||||
/// let dict = vec![("reverse", true)].into_py_dict(py);
|
||||
/// list.call_method(py, "sort", (), Some(dict)).unwrap();
|
||||
/// assert_eq!(list.extract::<Vec<i32>>(py).unwrap(), vec![7, 6, 5, 4, 3]);
|
||||
/// Python::with_gil(|py| {
|
||||
/// let list = vec![3, 6, 5, 4, 7].to_object(py);
|
||||
/// let dict = vec![("reverse", true)].into_py_dict(py);
|
||||
/// list.call_method(py, "sort", (), Some(dict)).unwrap();
|
||||
/// assert_eq!(list.extract::<Vec<i32>>(py).unwrap(), vec![7, 6, 5, 4, 3]);
|
||||
///
|
||||
/// let new_element = 1.to_object(py);
|
||||
/// list.call_method(py, "append", (new_element,), None).unwrap();
|
||||
/// assert_eq!(list.extract::<Vec<i32>>(py).unwrap(), vec![7, 6, 5, 4, 3, 1]);
|
||||
/// let new_element = 1.to_object(py);
|
||||
/// list.call_method(py, "append", (new_element,), None).unwrap();
|
||||
/// assert_eq!(list.extract::<Vec<i32>>(py).unwrap(), vec![7, 6, 5, 4, 3, 1]);
|
||||
/// });
|
||||
/// ```
|
||||
pub fn call_method(
|
||||
&self,
|
||||
|
|
|
@ -133,10 +133,7 @@ impl PyByteArray {
|
|||
/// ```
|
||||
/// # use pyo3::prelude::*;
|
||||
/// # use pyo3::types::PyByteArray;
|
||||
/// # use pyo3::types::IntoPyDict;
|
||||
/// # let gil = Python::acquire_gil();
|
||||
/// # let py = gil.python();
|
||||
/// #
|
||||
/// # Python::with_gil(|py| {
|
||||
/// let bytearray = PyByteArray::new(py, b"Hello World.");
|
||||
/// let mut copied_message = bytearray.to_vec();
|
||||
/// assert_eq!(b"Hello World.", copied_message.as_slice());
|
||||
|
@ -144,8 +141,8 @@ impl PyByteArray {
|
|||
/// copied_message[11] = b'!';
|
||||
/// assert_eq!(b"Hello World!", copied_message.as_slice());
|
||||
///
|
||||
/// let locals = [("bytearray", bytearray)].into_py_dict(py);
|
||||
/// py.run("assert bytearray == b'Hello World.'", None, Some(locals)).unwrap();
|
||||
/// pyo3::py_run!(py, bytearray, "assert bytearray == b'Hello World.'");
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
unsafe { self.as_bytes() }.to_vec()
|
||||
|
|
Loading…
Reference in a new issue