makepad-platform 1.0.0

Makepad platform layer
Documentation
#[allow(dead_code)]
use napi_ohos::sys::*;
use std::ffi::CString;
use std::ptr::null_mut;

fn value_type_to_string(val_type: &napi_valuetype) -> String {
    match *val_type {
        ValueType::napi_undefined => "undefined".to_string(),
        ValueType::napi_null => "null".to_string(),
        ValueType::napi_boolean => "boolean".to_string(),
        ValueType::napi_number => "number".to_string(),
        ValueType::napi_string => "string".to_string(),
        ValueType::napi_symbol => "symbol".to_string(),
        ValueType::napi_object => "object".to_string(),
        ValueType::napi_function => "function".to_string(),
        ValueType::napi_external => "external".to_string(),
        _ => "undefined".to_string(),
    }
}

pub fn get_value_string(raw_env: napi_env, str_value: napi_value) -> Option<String> {
    let mut len = 0;
    let napi_status =
        unsafe { napi_get_value_string_utf8(raw_env, str_value, null_mut(), 0, &mut len) };
    if napi_status != Status::napi_ok {
        crate::error!("failed to get string from napi_value");
        return None;
    }

    len += 1;
    let mut ret = Vec::with_capacity(len);
    let buf_ptr = ret.as_mut_ptr();
    let mut written_char_count = 0;
    let napi_status = unsafe {
        napi_get_value_string_utf8(raw_env, str_value, buf_ptr, len, &mut written_char_count)
    };
    if napi_status != Status::napi_ok {
        crate::error!("failed to get string from napi_value");
        return None;
    }

    let mut ret = std::mem::ManuallyDrop::new(ret);
    let buf_ptr = ret.as_mut_ptr();
    let bytes = unsafe { Vec::from_raw_parts(buf_ptr as *mut u8, written_char_count, len) };
    match String::from_utf8(bytes) {
        Err(e) => {
            crate::error!("failed to read utf8 string, {}", e);
            return None;
        }
        Ok(s) => Some(s),
    }
}

pub fn get_value_f64(raw_env: napi_env, f64_value: napi_value) -> Option<f64> {
    let mut result: f64 = 0.0;
    let napi_status = unsafe { napi_get_value_double(raw_env, f64_value, &mut result) };
    if napi_status != Status::napi_ok {
        crate::error!("failed to get f64 value from napi_value");
        return None;
    }
    return Some(result);
}

pub fn get_uv_loop(raw_env: napi_env) -> Option<*mut uv_loop_s> {
    let mut uv_loop = std::ptr::null_mut();
    let napi_status = unsafe { napi_get_uv_event_loop(raw_env, &mut uv_loop) };
    if napi_status != Status::napi_ok {
        crate::error!("failed to get uv loop from env");
        return None;
    }
    return Some(uv_loop);
}

pub fn get_object_property(
    raw_env: napi_env,
    object_value: napi_value,
    property_name: &str,
) -> Option<napi_value> {
    let cname = CString::new(property_name).ok()?;
    let mut result = null_mut();
    let napi_status =
        unsafe { napi_get_named_property(raw_env, object_value, cname.as_ptr(), &mut result) };
    if napi_status != Status::napi_ok {
        crate::error!("get property {} failed", property_name);
        return None;
    }
    let mut napi_type: napi_valuetype = 0;
    let _ = unsafe { napi_typeof(raw_env, result, &mut napi_type) };
    if napi_type == ValueType::napi_undefined {
        crate::error!("property {} is undefined", property_name);
        return None;
    }
    return Some(result);
}

pub fn get_global_this(raw_env: napi_env) -> Option<napi_value> {
    let mut global_obj = std::ptr::null_mut();
    let napi_status = unsafe { napi_get_global(raw_env, &mut global_obj) };
    if napi_status != Status::napi_ok {
        crate::error!("get global from env failed, error code = {}", napi_status);
        return None;
    }
    crate::log!("get global from env success");

    let mut global_this = std::ptr::null_mut();
    let napi_status = unsafe {
        napi_get_named_property(
            raw_env,
            global_obj,
            c"globalThis".as_ptr(),
            &mut global_this,
        )
    };
    if napi_status != Status::napi_ok {
        crate::error!(
            "get globalThis from global failed, error code = {}",
            napi_status
        );
        return None;
    }
    let mut napi_type: napi_valuetype = 0;
    let _ = unsafe { napi_typeof(raw_env, global_this, &mut napi_type) };
    if napi_type != ValueType::napi_object {
        crate::error!(
            "globalThis expect to be object, current data type = {}",
            value_type_to_string(&napi_type)
        );
        return None;
    }
    crate::log!("get globalThis from global success");
    return Some(global_this);
}

pub fn get_global_context(raw_env: napi_env) -> Option<napi_value> {
    let global_this = get_global_this(raw_env);
    if global_this.is_none() {
        return None;
    }

    let mut get_context_fn = std::ptr::null_mut();
    let napi_status = unsafe {
        napi_get_named_property(
            raw_env,
            global_this?,
            c"getContext".as_ptr(),
            &mut get_context_fn,
        )
    };
    if napi_status != Status::napi_ok {
        crate::error!(
            "get getContext from globalThis failed, error code = {}",
            napi_status
        );
        return None;
    }
    let mut napi_type: napi_valuetype = 0;
    let _ = unsafe { napi_typeof(raw_env, get_context_fn, &mut napi_type) };
    if napi_type != ValueType::napi_function {
        crate::error!(
            "getContext expect to be function, current data type = {}",
            value_type_to_string(&napi_type)
        );
        return None;
    }
    crate::log!("get getContext function success");

    let mut ctx_recv = std::ptr::null_mut();
    unsafe {
        let _ = napi_get_undefined(raw_env, &mut ctx_recv);
    }
    let mut get_context_result = std::ptr::null_mut();
    let napi_status = unsafe {
        napi_call_function(
            raw_env,
            ctx_recv,
            get_context_fn,
            0,
            std::ptr::null(),
            &mut get_context_result,
        )
    };
    if napi_status != Status::napi_ok {
        crate::error!("call getContext() failed, error code = {}", napi_status);
        return None;
    }
    napi_type = 0;
    let _ = unsafe { napi_typeof(raw_env, get_context_result, &mut napi_type) };
    if napi_type != ValueType::napi_object {
        crate::error!(
            "getContext() result expect to be object, current data type = {}",
            value_type_to_string(&napi_type)
        );
        return None;
    }
    crate::log!("call getContext() succcess");
    return Some(get_context_result);
}

pub fn get_files_dir(raw_env: napi_env) -> Option<String> {
    let ctx = get_global_context(raw_env);
    if ctx.is_none() {
        return None;
    }
    let file_dirs = get_object_property(raw_env, ctx?, "filesDir");
    if file_dirs.is_none() {
        crate::error!("failed to get filesDir from global context");
        return None;
    }
    let str_val = get_value_string(raw_env, file_dirs?);
    if str_val.is_none() {
        crate::error!("getContext().fileDir is not string value");
        return None;
    }
    return str_val;
}