mirror of
https://github.com/google/bumble.git
synced 2026-04-29 02:34:49 +00:00
* Autogenerate packet code in Rust from PDL (packet file copied from rootcanal) * Implement parsing of packets that have a type header * Expose Python APIs for sending HCI commands * Expose Python APIs for instantiating a local controller
125 lines
3.7 KiB
Rust
125 lines
3.7 KiB
Rust
// Copyright 2023 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! Types that wrap the Python API.
|
|
//!
|
|
//! Because mutability, aliasing, etc is all hidden behind Python, the normal Rust rules about
|
|
//! only one mutable reference to one piece of memory, etc, may not hold since using `&mut self`
|
|
//! instead of `&self` is only guided by inspection of the Python source, not the compiler.
|
|
//!
|
|
//! The modules are generally structured to mirror the Python equivalents.
|
|
|
|
// Re-exported to make it easy for users to depend on the same `PyObject`, etc
|
|
pub use pyo3;
|
|
use pyo3::{
|
|
prelude::*,
|
|
types::{PyDict, PyTuple},
|
|
};
|
|
pub use pyo3_asyncio;
|
|
|
|
pub mod assigned_numbers;
|
|
pub mod common;
|
|
pub mod controller;
|
|
pub mod core;
|
|
pub mod device;
|
|
pub mod drivers;
|
|
pub mod gatt_client;
|
|
pub mod hci;
|
|
pub mod host;
|
|
pub mod l2cap;
|
|
pub mod link;
|
|
pub mod logging;
|
|
pub mod profile;
|
|
pub mod transport;
|
|
|
|
/// Convenience extensions to [PyObject]
|
|
pub trait PyObjectExt: Sized {
|
|
/// Get a GIL-bound reference
|
|
fn gil_ref<'py>(&'py self, py: Python<'py>) -> &'py PyAny;
|
|
|
|
/// Extract any [FromPyObject] implementation from this value
|
|
fn extract_with_gil<T>(&self) -> PyResult<T>
|
|
where
|
|
T: for<'a> FromPyObject<'a>,
|
|
{
|
|
Python::with_gil(|py| self.gil_ref(py).extract::<T>())
|
|
}
|
|
|
|
/// If the Python object is a Python `None`, return a Rust `None`, otherwise `Some` with the mapped type
|
|
fn into_option<T>(self, map_obj: impl Fn(Self) -> T) -> Option<T> {
|
|
Python::with_gil(|py| {
|
|
if self.gil_ref(py).is_none() {
|
|
None
|
|
} else {
|
|
Some(map_obj(self))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
impl PyObjectExt for PyObject {
|
|
fn gil_ref<'py>(&'py self, py: Python<'py>) -> &'py PyAny {
|
|
self.as_ref(py)
|
|
}
|
|
}
|
|
|
|
/// Convenience extensions to [PyDict]
|
|
pub trait PyDictExt {
|
|
/// Set item in dict only if value is Some, otherwise do nothing.
|
|
fn set_opt_item<K: ToPyObject, V: ToPyObject>(&self, key: K, value: Option<V>) -> PyResult<()>;
|
|
}
|
|
|
|
impl PyDictExt for PyDict {
|
|
fn set_opt_item<K: ToPyObject, V: ToPyObject>(&self, key: K, value: Option<V>) -> PyResult<()> {
|
|
if let Some(value) = value {
|
|
self.set_item(key, value)?
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
/// Wrapper to make Rust closures ([Fn] implementations) callable from Python.
|
|
///
|
|
/// The Python callable form returns a Python `None`.
|
|
#[pyclass(name = "SubscribeCallback")]
|
|
pub(crate) struct ClosureCallback {
|
|
// can't use generics in a pyclass, so have to box
|
|
#[allow(clippy::type_complexity)]
|
|
callback: Box<dyn Fn(Python, &PyTuple, Option<&PyDict>) -> PyResult<()> + Send + 'static>,
|
|
}
|
|
|
|
impl ClosureCallback {
|
|
/// Create a new callback around the provided closure
|
|
pub fn new(
|
|
callback: impl Fn(Python, &PyTuple, Option<&PyDict>) -> PyResult<()> + Send + 'static,
|
|
) -> Self {
|
|
Self {
|
|
callback: Box::new(callback),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[pymethods]
|
|
impl ClosureCallback {
|
|
#[pyo3(signature = (*args, **kwargs))]
|
|
fn __call__(
|
|
&self,
|
|
py: Python<'_>,
|
|
args: &PyTuple,
|
|
kwargs: Option<&PyDict>,
|
|
) -> PyResult<Py<PyAny>> {
|
|
(self.callback)(py, args, kwargs).map(|_| py.None())
|
|
}
|
|
}
|