aboutsummaryrefslogtreecommitdiff
path: root/rust/src/wrapper/l2cap.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/wrapper/l2cap.rs')
-rw-r--r--rust/src/wrapper/l2cap.rs92
1 files changed, 92 insertions, 0 deletions
diff --git a/rust/src/wrapper/l2cap.rs b/rust/src/wrapper/l2cap.rs
new file mode 100644
index 0000000..5e0752e
--- /dev/null
+++ b/rust/src/wrapper/l2cap.rs
@@ -0,0 +1,92 @@
+// 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.
+
+//! L2CAP
+
+use crate::wrapper::{ClosureCallback, PyObjectExt};
+use pyo3::{intern, PyObject, PyResult, Python};
+
+/// L2CAP connection-oriented channel
+pub struct LeConnectionOrientedChannel(PyObject);
+
+impl LeConnectionOrientedChannel {
+ /// Create a LeConnectionOrientedChannel that wraps the provided obj.
+ pub(crate) fn from(obj: PyObject) -> Self {
+ Self(obj)
+ }
+
+ /// Queues data to be automatically sent across this channel.
+ pub fn write(&mut self, data: &[u8]) -> PyResult<()> {
+ Python::with_gil(|py| self.0.call_method1(py, intern!(py, "write"), (data,))).map(|_| ())
+ }
+
+ /// Wait for queued data to be sent on this channel.
+ pub async fn drain(&mut self) -> PyResult<()> {
+ Python::with_gil(|py| {
+ self.0
+ .call_method0(py, intern!(py, "drain"))
+ .and_then(|coroutine| pyo3_asyncio::tokio::into_future(coroutine.as_ref(py)))
+ })?
+ .await
+ .map(|_| ())
+ }
+
+ /// Register a callback to be called when the channel is closed.
+ pub fn on_close(
+ &mut self,
+ callback: impl Fn(Python) -> PyResult<()> + Send + 'static,
+ ) -> PyResult<()> {
+ let boxed = ClosureCallback::new(move |py, _args, _kwargs| callback(py));
+
+ Python::with_gil(|py| {
+ self.0
+ .call_method1(py, intern!(py, "add_listener"), ("close", boxed))
+ })
+ .map(|_| ())
+ }
+
+ /// Register a callback to be called when the channel receives data.
+ pub fn set_sink(
+ &mut self,
+ callback: impl Fn(Python, &[u8]) -> PyResult<()> + Send + 'static,
+ ) -> PyResult<()> {
+ let boxed = ClosureCallback::new(move |py, args, _kwargs| {
+ callback(py, args.get_item(0)?.extract()?)
+ });
+ Python::with_gil(|py| self.0.setattr(py, intern!(py, "sink"), boxed)).map(|_| ())
+ }
+
+ /// Disconnect the l2cap channel.
+ /// Must be called from a thread with a Python event loop, which should be true on
+ /// `tokio::main` and `async_std::main`.
+ ///
+ /// For more info, see https://awestlake87.github.io/pyo3-asyncio/master/doc/pyo3_asyncio/#event-loop-references-and-contextvars.
+ pub async fn disconnect(&mut self) -> PyResult<()> {
+ Python::with_gil(|py| {
+ self.0
+ .call_method0(py, intern!(py, "disconnect"))
+ .and_then(|coroutine| pyo3_asyncio::tokio::into_future(coroutine.as_ref(py)))
+ })?
+ .await
+ .map(|_| ())
+ }
+
+ /// Returns some information about the channel as a [String].
+ pub fn debug_string(&self) -> PyResult<String> {
+ Python::with_gil(|py| {
+ let str_obj = self.0.call_method0(py, intern!(py, "__str__"))?;
+ str_obj.gil_ref(py).extract()
+ })
+ }
+}