use super::{Actor, ActorBase};
use crate::{error::ffi::with_ffi_error, sensor::SensorData};
use autocxx::c_void;
use carla_sys::carla_rust::{
client::{FfiActor, FfiSensor},
sensor::FfiSensorData,
};
use cxx::SharedPtr;
use derivative::Derivative;
use static_assertions::assert_impl_all;
use std::mem;
type Callback = dyn FnMut(SharedPtr<FfiSensorData>) + Send + 'static;
#[derive(Clone, Derivative)]
#[derivative(Debug)]
#[repr(transparent)]
pub struct Sensor {
#[derivative(Debug = "ignore")]
inner: SharedPtr<FfiSensor>,
}
impl Sensor {
#[cfg_attr(
carla_version_0916,
doc = " See [carla.Sensor.stop](https://carla.readthedocs.io/en/0.9.16/python_api/#carla.Sensor.stop)"
)]
#[cfg_attr(
carla_version_0915,
doc = " See [carla.Sensor.stop](https://carla.readthedocs.io/en/0.9.15/python_api/#carla.Sensor.stop)"
)]
#[cfg_attr(
carla_version_0914,
doc = " See [carla.Sensor.stop](https://carla.readthedocs.io/en/0.9.14/python_api/#carla.Sensor.stop)"
)]
#[cfg_attr(
any(carla_version_0916, carla_version_0915, carla_version_0914),
doc = " in the Python API."
)]
pub fn stop(&self) -> crate::Result<()> {
with_ffi_error("stop", |e| {
self.inner.Stop(e);
})
}
#[cfg_attr(
carla_version_0916,
doc = " See [carla.Sensor.is_listening](https://carla.readthedocs.io/en/0.9.16/python_api/#carla.Sensor.is_listening)"
)]
#[cfg_attr(
carla_version_0915,
doc = " See [carla.Sensor.is_listening](https://carla.readthedocs.io/en/0.9.15/python_api/#carla.Sensor.is_listening)"
)]
#[cfg_attr(
carla_version_0914,
doc = " See [carla.Sensor.is_listening](https://carla.readthedocs.io/en/0.9.14/python_api/#carla.Sensor.is_listening)"
)]
#[cfg_attr(
any(carla_version_0916, carla_version_0915, carla_version_0914),
doc = " in the Python API."
)]
pub fn is_listening(&self) -> crate::Result<bool> {
with_ffi_error("is_listening", |e| self.inner.IsListening(e))
}
#[cfg_attr(
carla_version_0916,
doc = " See [carla.Sensor.listen](https://carla.readthedocs.io/en/0.9.16/python_api/#carla.Sensor.listen)"
)]
#[cfg_attr(
carla_version_0915,
doc = " See [carla.Sensor.listen](https://carla.readthedocs.io/en/0.9.15/python_api/#carla.Sensor.listen)"
)]
#[cfg_attr(
carla_version_0914,
doc = " See [carla.Sensor.listen](https://carla.readthedocs.io/en/0.9.14/python_api/#carla.Sensor.listen)"
)]
#[cfg_attr(
any(carla_version_0916, carla_version_0915, carla_version_0914),
doc = " in the Python API."
)]
pub fn listen<F>(&self, mut callback: F) -> crate::Result<()>
where
F: FnMut(SensorData) + Send + 'static,
{
with_ffi_error("listen", |e| {
unsafe {
let fn_ptr = {
let fn_ = move |ptr: SharedPtr<FfiSensorData>| {
let data = SensorData::from_cxx(ptr);
(callback)(data);
};
let fn_: Box<Callback> = Box::new(fn_);
let fn_ = Box::new(fn_);
let fn_: *mut Box<Callback> = Box::into_raw(fn_);
fn_ as *mut c_void
};
let caller_ptr = caller as *mut c_void;
let deleter_ptr = deleter as *mut c_void;
self.inner.Listen(caller_ptr, fn_ptr, deleter_ptr, e);
}
})
}
pub fn listen_to_gbuffer<F>(&self, gbuffer_id: u32, mut callback: F) -> crate::Result<()>
where
F: FnMut(SensorData) + Send + 'static,
{
with_ffi_error("listen_to_gbuffer", |e| unsafe {
let fn_ptr = {
let fn_ = move |ptr: SharedPtr<FfiSensorData>| {
let data = SensorData::from_cxx(ptr);
(callback)(data);
};
let fn_: Box<Callback> = Box::new(fn_);
let fn_ = Box::new(fn_);
let fn_: *mut Box<Callback> = Box::into_raw(fn_);
fn_ as *mut c_void
};
let caller_ptr = caller as *mut c_void;
let deleter_ptr = deleter as *mut c_void;
self.inner
.ListenToGBuffer(gbuffer_id, caller_ptr, fn_ptr, deleter_ptr, e);
})
}
pub fn is_listening_gbuffer(&self, gbuffer_id: u32) -> crate::Result<bool> {
with_ffi_error("is_listening_gbuffer", |e| {
self.inner.IsListeningGBuffer(gbuffer_id, e)
})
}
pub fn stop_gbuffer(&self, gbuffer_id: u32) -> crate::Result<()> {
with_ffi_error("stop_gbuffer", |e| {
self.inner.StopGBuffer(gbuffer_id, e);
})
}
#[cfg(carla_0915)]
pub fn enable_for_ros(&self) -> crate::Result<()> {
with_ffi_error("enable_for_ros", |e| {
self.inner.EnableForROS(e);
})
}
#[cfg(carla_0915)]
pub fn disable_for_ros(&self) -> crate::Result<()> {
with_ffi_error("disable_for_ros", |e| {
self.inner.DisableForROS(e);
})
}
#[cfg(carla_0915)]
pub fn is_enabled_for_ros(&self) -> crate::Result<bool> {
with_ffi_error("is_enabled_for_ros", |e| self.inner.IsEnabledForROS(e))
}
pub(crate) fn from_cxx(ptr: SharedPtr<FfiSensor>) -> Option<Self> {
if ptr.is_null() {
None
} else {
Some(Self { inner: ptr })
}
}
}
impl ActorBase for Sensor {
fn cxx_actor(&self) -> SharedPtr<FfiActor> {
self.inner.to_actor()
}
}
impl TryFrom<Actor> for Sensor {
type Error = Actor;
fn try_from(value: Actor) -> Result<Self, Self::Error> {
let ptr = value.inner.to_sensor();
Self::from_cxx(ptr).ok_or(value)
}
}
unsafe extern "C" fn caller(fn_: *mut c_void, arg: *mut SharedPtr<FfiSensorData>) {
if fn_.is_null() || arg.is_null() {
eprintln!(
"ERROR: Null pointer in sensor callback - fn_: {:p}, arg: {:p}",
fn_, arg
);
return;
}
let fn_ = fn_ as *mut Box<Callback>;
unsafe {
let arg = (*arg).clone();
(*fn_)(arg);
}
}
unsafe extern "C" fn deleter(fn_: *mut c_void) {
if fn_.is_null() {
eprintln!("ERROR: Null pointer in sensor deleter");
return;
}
let fn_ = fn_ as *mut Box<Callback>;
let fn_: Box<Box<Callback>> = unsafe { Box::from_raw(fn_) };
mem::drop(fn_);
}
assert_impl_all!(Sensor: Send, Sync);