ohos-web-binding 0.1.1

OpenHarmony's web binding for rust
use std::{ffi::CString, ptr::NonNull, sync::LazyLock};

use ohos_web_sys::{
    ArkWeb_ControllerAPI, ArkWeb_NativeAPIVariantKind_ARKWEB_NATIVE_CONTROLLER, ArkWeb_ProxyObject,
    OH_ArkWeb_GetNativeAPI,
};

use crate::{ark_web_member_missing, ArkWebError};

pub struct Controller {
    raw: NonNull<ArkWeb_ControllerAPI>,
}

impl Controller {
    pub fn new() -> Self {
        let ret = unsafe {
            OH_ArkWeb_GetNativeAPI(ArkWeb_NativeAPIVariantKind_ARKWEB_NATIVE_CONTROLLER)
                as *mut ArkWeb_ControllerAPI
        };
        #[cfg(debug_assertions)]
        assert!(
            !ret.is_null(),
            "Failed to get Controller API by OH_ArkWeb_GetNativeAPI"
        );

        Self {
            raw: unsafe { NonNull::new_unchecked(ret) },
        }
    }

    pub fn check_member_missing(&self, member: &str) -> Result<(), ArkWebError> {
        match member {
            "runJavaScript" => {
                if !ark_web_member_missing!(self.raw.as_ptr(), runJavaScript) {
                    Ok(())
                } else {
                    Err(ArkWebError::ArkWebApiMemberMissing(member.to_string()))
                }
            }
            "registerJavaScriptProxy" => {
                if !ark_web_member_missing!(self.raw.as_ptr(), registerJavaScriptProxy) {
                    Ok(())
                } else {
                    Err(ArkWebError::ArkWebApiMemberMissing(member.to_string()))
                }
            }
            "deleteJavaScriptRegister" => {
                if !ark_web_member_missing!(self.raw.as_ptr(), deleteJavaScriptRegister) {
                    Ok(())
                } else {
                    Err(ArkWebError::ArkWebApiMemberMissing(member.to_string()))
                }
            }
            "refresh" => {
                if !ark_web_member_missing!(self.raw.as_ptr(), refresh) {
                    Ok(())
                } else {
                    Err(ArkWebError::ArkWebApiMemberMissing(member.to_string()))
                }
            }
            "registerAsyncJavaScriptProxy" => {
                if !ark_web_member_missing!(self.raw.as_ptr(), registerAsyncJavaScriptProxy) {
                    Ok(())
                } else {
                    Err(ArkWebError::ArkWebApiMemberMissing(member.to_string()))
                }
            }
            "createWebMessagePorts" => {
                if !ark_web_member_missing!(self.raw.as_ptr(), createWebMessagePorts) {
                    Ok(())
                } else {
                    Err(ArkWebError::ArkWebApiMemberMissing(member.to_string()))
                }
            }
            "destroyWebMessagePorts" => {
                if !ark_web_member_missing!(self.raw.as_ptr(), destroyWebMessagePorts) {
                    Ok(())
                } else {
                    Err(ArkWebError::ArkWebApiMemberMissing(member.to_string()))
                }
            }
            "postWebMessage" => {
                if !ark_web_member_missing!(self.raw.as_ptr(), postWebMessage) {
                    Ok(())
                } else {
                    Err(ArkWebError::ArkWebApiMemberMissing(member.to_string()))
                }
            }
            "getLastJavascriptProxyCallingFrameUrl" => {
                if !ark_web_member_missing!(
                    self.raw.as_ptr(),
                    getLastJavascriptProxyCallingFrameUrl
                ) {
                    Ok(())
                } else {
                    Err(ArkWebError::ArkWebApiMemberMissing(member.to_string()))
                }
            }
            _ => Ok(()),
        }
    }

    pub fn register_javascript_proxy(
        &self,
        web_tag: String,
        proxy_object: *const ArkWeb_ProxyObject,
    ) -> Result<(), ArkWebError> {
        self.check_member_missing("registerJavaScriptProxy")?;

        let tag = CString::new(web_tag).map_err(|e| {
            ArkWebError::JsApiRegisterFailed(format!(
                "Failed to create CString when call registerJavaScriptProxy: {}",
                e
            ))
        })?;

        unsafe {
            if let Some(cb) = (*self.raw.as_ptr()).registerJavaScriptProxy {
                cb(tag.as_ptr().cast(), proxy_object);
            }
        }
        Ok(())
    }

    pub fn refresh(&self, web_tag: String) -> Result<(), ArkWebError> {
        let tag = CString::new(web_tag).map_err(|e| {
            ArkWebError::JsApiRegisterFailed(format!(
                "Failed to create CString when call refresh: {}",
                e
            ))
        })?;

        unsafe {
            if let Some(cb) = (*self.raw.as_ptr()).refresh {
                cb(tag.as_ptr().cast());
            }
        }
        Ok(())
    }
}

unsafe impl Send for Controller {}
unsafe impl Sync for Controller {}

pub static ARK_WEB_CONTROLLER_API: LazyLock<Controller> = LazyLock::new(Controller::new);