use crate::ffi::errors::{ErrorHandle, Status};
use crate::ffi::{borrow, borrow_text, Buffer, Slice};
use crate::helpers::hpack::{Decoder, Encoder, HeaderField};
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Field {
pub name: Slice,
pub value: Slice,
}
pub unsafe fn parse_fields(fields: *const Field, count: usize) -> Option<Vec<HeaderField>> {
if fields.is_null() {
return (count == 0).then(Vec::new);
}
let mut parsed = Vec::with_capacity(count);
for index in 0..count {
let field = unsafe { *fields.add(index) };
let name = unsafe { borrow_text(field.name.data, field.name.len) }?;
let value = unsafe { borrow_text(field.value.data, field.value.len) }?;
parsed.push(HeaderField::new(name, value));
}
Some(parsed)
}
pub struct Fields(pub Vec<HeaderField>);
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_fields_free(fields: *mut Fields) {
if !fields.is_null() {
drop(unsafe { Box::from_raw(fields) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_fields_count(fields: *const Fields) -> usize {
unsafe { fields.as_ref() }.map_or(0, |fields| fields.0.len())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_fields_name(fields: *const Fields, index: usize) -> Slice {
Slice::maybe(unsafe { fields.as_ref() }.and_then(|fields| fields.0.get(index)).map(|field| field.name.as_str()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_fields_value(fields: *const Fields, index: usize) -> Slice {
Slice::maybe(unsafe { fields.as_ref() }.and_then(|fields| fields.0.get(index)).map(|field| field.value.as_str()))
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_hpack_encoder_new() -> *mut Encoder {
Box::into_raw(Box::new(Encoder::new()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_hpack_encoder_free(encoder: *mut Encoder) {
if !encoder.is_null() {
drop(unsafe { Box::from_raw(encoder) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_hpack_encoder_set_dynamic_table_size(encoder: *mut Encoder, max_size: usize) -> bool {
let Some(encoder) = (unsafe { encoder.as_mut() }) else {
return false;
};
encoder.set_dynamic_table_size(max_size);
true
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_hpack_encode(encoder: *mut Encoder, fields: *const Field, field_count: usize) -> Buffer {
let (Some(encoder), Some(fields)) = (unsafe { encoder.as_mut() }, unsafe { parse_fields(fields, field_count) }) else {
return Buffer::EMPTY;
};
Buffer::new(encoder.encode(&fields))
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_hpack_decoder_new() -> *mut Decoder {
Box::into_raw(Box::new(Decoder::new()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_hpack_decoder_free(decoder: *mut Decoder) {
if !decoder.is_null() {
drop(unsafe { Box::from_raw(decoder) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_hpack_decoder_set_max_decoded_size(decoder: *mut Decoder, max_size: usize) -> bool {
let Some(decoder) = (unsafe { decoder.as_mut() }) else {
return false;
};
decoder.set_max_decoded_size(max_size);
true
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_hpack_decoder_set_dynamic_table_size(decoder: *mut Decoder, max_size: usize) -> bool {
let Some(decoder) = (unsafe { decoder.as_mut() }) else {
return false;
};
decoder.set_dynamic_table_size(max_size);
true
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_hpack_decode(decoder: *mut Decoder, block: *const u8, block_len: usize, out: *mut *mut Fields, error: *mut *mut ErrorHandle) -> Status {
let Some(decoder) = (unsafe { decoder.as_mut() }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
if out.is_null() {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
}
let Some(block) = (unsafe { borrow(block, block_len) }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
match decoder.decode(block) {
Ok(fields) => {
unsafe { *out = Box::into_raw(Box::new(Fields(fields))) };
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &crate::errors::Error::from(failure)) },
}
}