use std::ffi::CStr;
use std::marker::PhantomData;
use std::ptr::NonNull;
use crate::grpc_sys::{
self, grpc_auth_context, grpc_auth_property, grpc_auth_property_iterator, grpc_call,
};
pub struct AuthContext {
ctx: NonNull<grpc_auth_context>,
}
impl AuthContext {
pub(crate) unsafe fn from_call_ptr(call: *mut grpc_call) -> Option<Self> {
NonNull::new(grpc_sys::grpc_call_auth_context(call)).map(|ctx| AuthContext { ctx })
}
pub fn peer_identity_property_name(&self) -> Option<&str> {
unsafe {
let p = grpc_sys::grpc_auth_context_peer_identity_property_name(self.ctx.as_ref());
if p.is_null() {
None
} else {
Some(CStr::from_ptr(p).to_str().expect("valid UTF-8 data"))
}
}
}
pub fn peer_is_authenticated(&self) -> bool {
unsafe { grpc_sys::grpc_auth_context_peer_is_authenticated(self.ctx.as_ref()) != 0 }
}
pub fn peer_identity(&self) -> AuthPropertyIter {
unsafe {
let iter = grpc_sys::grpc_auth_context_peer_identity(self.ctx.as_ref());
AuthPropertyIter {
iter,
_lifetime: PhantomData,
}
}
}
}
impl<'a> IntoIterator for &'a AuthContext {
type Item = AuthProperty<'a>;
type IntoIter = AuthPropertyIter<'a>;
fn into_iter(self) -> Self::IntoIter {
unsafe {
let iter = grpc_sys::grpc_auth_context_property_iterator(self.ctx.as_ref());
AuthPropertyIter {
iter,
_lifetime: PhantomData,
}
}
}
}
impl Drop for AuthContext {
fn drop(&mut self) {
unsafe { grpc_sys::grpc_auth_context_release(self.ctx.as_ptr()) }
}
}
pub struct AuthPropertyIter<'a> {
iter: grpc_auth_property_iterator,
_lifetime: PhantomData<&'a grpc_auth_property_iterator>,
}
impl<'a> Iterator for AuthPropertyIter<'a> {
type Item = AuthProperty<'a>;
fn next(&mut self) -> Option<Self::Item> {
let prop = unsafe { grpc_sys::grpc_auth_property_iterator_next(&mut self.iter) };
if prop.is_null() {
None
} else {
Some(AuthProperty {
prop,
_lifetime: PhantomData,
})
}
}
}
pub struct AuthProperty<'a> {
prop: *const grpc_auth_property,
_lifetime: PhantomData<&'a grpc_auth_property>,
}
impl<'a> AuthProperty<'a> {
pub fn name(&self) -> &'a str {
unsafe { CStr::from_ptr((*self.prop).name) }
.to_str()
.expect("Auth property name should be valid UTF-8 data")
}
pub fn value(&self) -> &'a [u8] {
unsafe {
std::slice::from_raw_parts((*self.prop).value as *const u8, (*self.prop).value_length)
}
}
pub fn value_str(&self) -> Result<&'a str, std::str::Utf8Error> {
std::str::from_utf8(self.value())
}
}