use std::cell::{Ref, RefMut};
use libcoap_sys::{
coap_session_get_app_data, coap_session_get_type, coap_session_reference, coap_session_release,
coap_session_set_app_data, coap_session_t, coap_session_type_t,
};
use crate::mem::CoapFfiRcCell;
use crate::mem::DropInnerExclusively;
use super::{CoapSessionCommon, CoapSessionInner, CoapSessionInnerProvider};
impl DropInnerExclusively for CoapServerSession<'_> {
fn drop_exclusively(self) {
let sess_ref = self.inner.clone();
std::mem::drop(self);
sess_ref.drop_exclusively();
}
}
#[derive(Debug, Clone)]
pub struct CoapServerSession<'a> {
inner: CoapFfiRcCell<CoapServerSessionInner<'a>>,
}
#[derive(Debug)]
struct CoapServerSessionInner<'a> {
inner: CoapSessionInner<'a>,
}
impl CoapServerSession<'_> {
pub(crate) unsafe fn initialize_raw<'a>(raw_session: *mut coap_session_t) -> CoapServerSession<'a> {
assert!(!raw_session.is_null(), "provided raw session was null");
let raw_session_type = coap_session_get_type(raw_session);
let inner = CoapSessionInner::new(raw_session);
let session_inner = match raw_session_type {
coap_session_type_t::COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
coap_session_type_t::COAP_SESSION_TYPE_CLIENT => {
panic!("attempted to create server session from raw client session")
},
coap_session_type_t::COAP_SESSION_TYPE_SERVER => CoapServerSessionInner { inner },
coap_session_type_t::COAP_SESSION_TYPE_HELLO => CoapServerSessionInner { inner },
_ => unreachable!("unknown session type"),
};
let session_ref = CoapFfiRcCell::new(session_inner);
coap_session_set_app_data(raw_session, session_ref.create_raw_weak());
coap_session_reference(raw_session);
CoapServerSession { inner: session_ref }
}
pub(crate) unsafe fn from_raw<'a>(raw_session: *mut coap_session_t) -> CoapServerSession<'a> {
assert!(!raw_session.is_null(), "provided raw session was null");
let raw_session_type = coap_session_get_type(raw_session);
match raw_session_type {
coap_session_type_t::COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
coap_session_type_t::COAP_SESSION_TYPE_SERVER | coap_session_type_t::COAP_SESSION_TYPE_HELLO => {
let raw_app_data_ptr = coap_session_get_app_data(raw_session);
assert!(!raw_app_data_ptr.is_null(), "provided raw session has no app data");
coap_session_reference(raw_session);
CoapServerSession {
inner: CoapFfiRcCell::clone_raw_rc(raw_app_data_ptr),
}
},
coap_session_type_t::COAP_SESSION_TYPE_CLIENT => {
panic!("attempted to create CoapServerSession from raw client session")
},
_ => unreachable!("unknown session type"),
}
}
}
impl<'a> Drop for CoapServerSession<'a> {
fn drop(&mut self) {
let raw_session = self.inner.borrow_mut().inner.raw_session;
unsafe {
coap_session_release(raw_session);
}
}
}
impl<'a> CoapSessionInnerProvider<'a> for CoapServerSession<'a> {
fn inner_ref<'b>(&'b self) -> Ref<'b, CoapSessionInner<'a>> {
Ref::map(self.inner.borrow(), |v| &v.inner)
}
fn inner_mut<'b>(&'b self) -> RefMut<'b, CoapSessionInner<'a>> {
RefMut::map(self.inner.borrow_mut(), |v| &mut v.inner)
}
}
impl<'a, T: CoapSessionCommon<'a>> PartialEq<T> for CoapServerSession<'_> {
fn eq(&self, other: &T) -> bool {
self.if_index() == other.if_index()
&& unsafe { self.raw_session() == other.raw_session() }
&& self.addr_local() == other.addr_local()
&& self.addr_remote() == other.addr_remote()
}
}
impl Eq for CoapServerSession<'_> {}
impl Drop for CoapServerSessionInner<'_> {
fn drop(&mut self) {
unsafe {
let app_data = coap_session_get_app_data(self.inner.raw_session);
assert!(!app_data.is_null());
std::mem::drop(CoapFfiRcCell::<CoapServerSessionInner>::raw_ptr_to_weak(app_data));
}
}
}