use std::{ffi::c_void, mem::ManuallyDrop, ptr::NonNull};
use ohos_web_sys::{
ArkWeb_HttpBodyStream, OH_ArkWebHttpBodyStream_GetSize, OH_ArkWebHttpBodyStream_GetUserData,
OH_ArkWebHttpBodyStream_Init, OH_ArkWebHttpBodyStream_IsChunked, OH_ArkWebHttpBodyStream_IsEof,
OH_ArkWebHttpBodyStream_IsInMemory, OH_ArkWebHttpBodyStream_Read,
OH_ArkWebHttpBodyStream_SetReadCallback, OH_ArkWebHttpBodyStream_SetUserData,
};
pub struct HttpBodyStream {
raw: NonNull<ArkWeb_HttpBodyStream>,
}
struct ReadCallbackContext {
callback: Box<dyn FnMut(Vec<u8>)>,
}
impl HttpBodyStream {
pub fn new(raw: *mut ArkWeb_HttpBodyStream) -> Self {
unsafe {
OH_ArkWebHttpBodyStream_Init(raw, None);
Self {
raw: NonNull::new_unchecked(raw),
}
}
}
pub fn is_chunked(&self) -> bool {
unsafe { OH_ArkWebHttpBodyStream_IsChunked(self.raw.as_ptr()) }
}
pub fn is_eof(&self) -> bool {
unsafe { OH_ArkWebHttpBodyStream_IsEof(self.raw.as_ptr()) }
}
pub fn is_in_memory(&self) -> bool {
unsafe { OH_ArkWebHttpBodyStream_IsInMemory(self.raw.as_ptr()) }
}
pub fn read<F>(&self, size: usize, mut callback: F)
where
F: FnMut(Vec<u8>),
{
let mut buf: Vec<u8> = Vec::with_capacity(size);
let buf_ptr = buf.as_mut_ptr();
let static_callback = unsafe {
std::mem::transmute::<Box<dyn FnMut(Vec<u8>)>, Box<dyn FnMut(Vec<u8>) + 'static>>(
Box::new(move |buf| {
callback(buf);
}),
)
};
let ctx = ReadCallbackContext {
callback: static_callback,
};
let ctx_ptr = Box::into_raw(Box::new(ctx)) as *mut c_void;
unsafe {
OH_ArkWebHttpBodyStream_SetUserData(self.raw.as_ptr(), ctx_ptr);
OH_ArkWebHttpBodyStream_SetReadCallback(self.raw.as_ptr(), Some(read_callback));
OH_ArkWebHttpBodyStream_Read(self.raw.as_ptr(), buf_ptr, size as _);
};
}
pub fn size(&self) -> u64 {
unsafe { OH_ArkWebHttpBodyStream_GetSize(self.raw.as_ptr()) }
}
}
extern "C" fn read_callback(
http_body_stream: *const ArkWeb_HttpBodyStream,
buffer: *mut u8,
bytes_read: i32,
) {
unsafe {
let user_data_ptr = OH_ArkWebHttpBodyStream_GetUserData(http_body_stream);
let mut ctx = ManuallyDrop::new(Box::from_raw(user_data_ptr as *mut ReadCallbackContext));
let data = std::slice::from_raw_parts(buffer, bytes_read as usize).to_vec();
(ctx.callback)(data);
}
}