使用Node-API接口操作bigint类型值
=======================

#### 简介

BigInt是ArkTS中用于表示任意精度整数的数据类型，它能够处理比Number类型更大范围的整数值。通过Node-API提供的接口，可以在Node-API模块中创建、获取和操作BigInt类型值，从而实现与BigInt相关的功能扩展。

#### 基本概念

在使用Node-API接口操作BigInt类型值时，需要理解以下基本概念：

*   **BigInt类型：** BigInt是ArkTS中的一种数据类型，用于表示任意精度的整数。与Number类型不同，BigInt类型可以精确表示非常大的整数，而不会丢失精度或溢出。
*   **BigInt创建：** 使用Node-API提供的接口，可以通过传递C的int64或uint64数据来创建对应的ArkTS BigInt。这使得在Node-API模块中可以方便地创建BigInt类型值。
*   **BigInt操作：** Node-API提供了多个接口用于操作BigInt类型值。通过这些接口，可以获取BigInt的数值，进行数值转换，以及执行常见的算术和位运算操作。

#### 场景和功能介绍

| 接口 | 描述 |
| :-- | :-- |
| napi\_create\_bigint\_int64 | 用于创建64位带符号整数（int64）的BigInt对象的函数。 |
| napi\_create\_bigint\_uint64 | 用于创建64位无符号整数（uint64）的BigInt对象的函数。 |
| napi\_create\_bigint\_words | 用于根据提供的64位无符号（uint64）整数创建BigInt对象的函数。 |
| napi\_get\_value\_bigint\_int64 | 用于从BigInt对象中获取64位带符号整数（int64）值的函数。 |
| napi\_get\_value\_bigint\_uint64 | 用于从BigInt对象中获取64位无符号整数（uint64）值的函数。 |
| napi\_get\_value\_bigint\_words | 用于从BigInt对象中获取底层的64位无符号（uint64）整数。 |

#### 使用示例

Node-API接口开发流程参考[使用Node-API实现跨语言交互开发流程](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/use-napi-process)，本文仅对接口对应C++及ArkTS相关代码进行展示。

本文cpp部分代码所需引用的头文件如下：

#include "napi/native\_api.h"
#include "hilog/log.h"

本文ArkTS侧示例代码所需的模块导入如下：

import { hilog } from '@kit.PerformanceAnalysisKit';
import testNapi from 'libentry.so';

#### \[h2\]napi\_create\_bigint\_int64

这个函数用于在给定的Node-API环境中依据一个带有符号的64位整数创建一个ArkTS的BigInt对象。

cpp部分代码

// napi\_create\_bigint\_int64
static napi\_value CreateBigintInt64t(napi\_env env, napi\_callback\_info info)
{
    // 声明int64\_t的变量value
    int64\_t value = -5555555555555555555;
    // 将value转化为napi\_value类型返回
    napi\_value returnValue = nullptr;
    napi\_create\_bigint\_int64(env, value, &returnValue);
    return returnValue;
}

接口声明

index.d.ts

export const createBigintInt64t: () => bigint; // napi\_create\_bigint\_int64

ArkTS侧示例代码

// napi\_create\_bigint\_int64
hilog.info(0x0000, 'testTag', 'Test Node-API napi\_create\_bigint\_int64: %{public}d',
  testNapi.createBigintInt64t());

#### \[h2\]napi\_create\_bigint\_uint64

这个函数用于在给定的Node-API环境中依据一个无符号的64位整数创建一个ArkTS的BigInt对象。

cpp部分代码

// napi\_create\_bigint\_uint64
static napi\_value CreateBigintUint64t(napi\_env env, napi\_callback\_info info)
{
    // 声明uint64\_t的变量value
    uint64\_t value = 5555555555555555555;
    // 将value转化为napi\_value类型返回
    napi\_value returnValue = nullptr;
    napi\_create\_bigint\_uint64(env, value, &returnValue);
    return returnValue;
}

接口声明

index.d.ts

export const createBigintUint64t: () => bigint; // napi\_create\_bigint\_uint64

ArkTS侧示例代码

// napi\_create\_bigint\_uint64
hilog.info(0x0000, 'testTag', 'Test Node-API napi\_create\_bigint\_uint64: %{public}d',
  testNapi.createBigintUint64t());

#### \[h2\]napi\_create\_bigint\_words

这个函数用于在给定的Node-API环境中由一系列无符号64位整数创建一个ArkTS的BigInt对象。

cpp部分代码

// napi\_create\_bigint\_words
static napi\_value CreateBigintWords(napi\_env env, napi\_callback\_info info)
{
    // 使用napi\_create\_bigint\_words接口创建一个BigInt对象
    int signBit = 0;
    size\_t wordCount = 3;
    uint64\_t words\[\] = {12ULL, 34ULL, 56ULL};
    napi\_value returnValue = nullptr;
    napi\_status status = napi\_create\_bigint\_words(env, signBit, wordCount, words, &returnValue);
    if (status != napi\_ok) {
        napi\_throw\_error(env, nullptr, "napi\_create\_bigint\_words fail");
        return nullptr;
    }
    return returnValue;
}

接口声明

index.d.ts

export const createBigintWords: () => bigint | undefined; // napi\_create\_bigint\_words

ArkTS侧示例代码

// napi\_create\_bigint\_words
try {
  hilog.info(0x0000, 'testTag', 'Test Node-API napi\_create\_bigint\_words: %{public}d',
    testNapi.createBigintWords());
  // ...
} catch (error) {
  hilog.error(0x0000, 'testTag', 'Test Node-API NapiGetValueBigint: %{public}s', error.message);
  // ...
}

#### \[h2\]napi\_get\_value\_bigint\_int64

用于从传入的参数中提取64位整数的BigInt数据，以供后续处理。

cpp部分代码

// napi\_get\_value\_bigint\_int64
static napi\_value GetValueBigintInt64t(napi\_env env, napi\_callback\_info info)
{
    size\_t argc = 1;
    napi\_value args\[1\] = {nullptr};
    napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    // 从传入的参数中提取64位整数的BigInt数据
    int64\_t value = 0;
    bool lossLess = false;
    napi\_status status = napi\_get\_value\_bigint\_int64(env, args\[0\], &value, &lossLess);
    // 判断从ArkTS侧获取bigint是否为无损转换，如果不是抛出异常
    if (!lossLess) {
        napi\_throw\_error(env, nullptr, "BigInt values have not been lossless converted");
        return nullptr;
    }
    // 如果接口调用成功正常调用则返回true给ArkTS侧
    napi\_value returnValue = nullptr;
    if (status == napi\_ok) {
        napi\_get\_boolean(env, true, &returnValue);
        return returnValue;
    } else {
        napi\_throw\_error(env, nullptr, "napi\_get\_value\_bigint\_int64 failed");
        return nullptr;
    }
}

接口声明

index.d.ts

export const getValueBigintInt64t: (bigInt64: bigint) => boolean | undefined; // napi\_get\_value\_bigint\_int64

ArkTS侧示例代码

// napi\_get\_value\_bigint\_int64
let bigInt = BigInt(-5555555555555555);
try {
  hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_value\_bigint\_int64: %{public}s',
    JSON.stringify(testNapi.getValueBigintInt64t(bigInt)));
  // ...
} catch (error) {
  hilog.error(0x0000, 'testTag', 'Test Node-API NapiGetValueBigint: %{public}s', error.message);
  // ...
}

#### \[h2\]napi\_get\_value\_bigint\_uint64

用于从传入的参数中提取无符号64位整数的BigInt数据，以供后续处理。

cpp部分代码

// napi\_get\_value\_bigint\_uint64
static napi\_value GetValueBigintUint64t(napi\_env env, napi\_callback\_info info)
{
    size\_t argc = 1;
    napi\_value args\[1\] = {nullptr};
    napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    // 从参数值中获取BigInt的数值
    uint64\_t value = 0;
    bool lossLess = false;
    napi\_status status = napi\_get\_value\_bigint\_uint64(env, args\[0\], &value, &lossLess);
    // 判断从ArkTS侧获取bigint是否为无损转换，如果不是抛出异常
    if (!lossLess) {
        napi\_throw\_error(env, nullptr, "BigInt values have no lossless converted");
        return nullptr;
    }
    // 如果接口调用成功正常调用则返回true给ArkTS侧
    napi\_value returnValue = nullptr;
    napi\_get\_boolean(env, status == napi\_ok, &returnValue);
    return returnValue;
}

接口声明

index.d.ts

export const getValueBigintUint64t: (bigUint64: bigint) => boolean | undefined; // napi\_get\_value\_bigint\_uint64

ArkTS侧示例代码

// napi\_get\_value\_bigint\_uint64
let bigUint = BigInt(5555555555555555);
try {
  hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_value\_bigint\_uint64: %{public}s',
    JSON.stringify(testNapi.getValueBigintUint64t(bigUint)));
  // ...
} catch (error) {
  hilog.error(0x0000, 'testTag', 'Test Node-API NapiGetValueBigint: %{public}s', error.message);
  // ...
}

#### \[h2\]napi\_get\_value\_bigint\_words

用于从ArkTS对象中获取其符号位和底层64位无符号整数数组表示。

cpp部分代码

// napi\_get\_value\_bigint\_words
static napi\_value GetValueBigintWords(napi\_env env, napi\_callback\_info info)
{
    size\_t argc = 1;
    napi\_value args\[1\] = {nullptr};
    napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    int signBit = 0;
    size\_t wordCount = 0;
    // 调用napi\_get\_value\_bigint\_words接口获取wordCount
    napi\_status status = napi\_get\_value\_bigint\_words(env, args\[0\], nullptr, &wordCount, nullptr);
    OH\_LOG\_INFO(LOG\_APP, "Node-API , wordCount:%{public}d.", wordCount);
    if (status != napi\_ok) {
        OH\_LOG\_ERROR(LOG\_APP, "Node-API , get wordCount fail, status:%{public}d.", status);
        napi\_throw\_error(env, nullptr, "napi\_get\_value\_bigint\_words call failed");
        return nullptr;
    }
    if (wordCount == 0) {
        OH\_LOG\_ERROR(LOG\_APP, "Node-API , wordCount is 0, invalid BigInt or empty value.");
        napi\_throw\_error(env, nullptr, "napi\_get\_value\_bigint\_words returned wordCount 0");
        return nullptr;
    }
    
    const size\_t MAX\_ALLOWED\_WORDS = 1024; // 限制wordCount上限（业务防护，根据实际场景调整）示例：最多允许1024个uint64\_t（8KB）
    if (wordCount > MAX\_ALLOWED\_WORDS) {
        OH\_LOG\_ERROR(LOG\_APP, "Node-API , wordCount(%{public}zu) exceeds max limit(%{public}zu)",
            wordCount, MAX\_ALLOWED\_WORDS);
        napi\_throw\_error(env, nullptr, "wordCount is too large");
        return nullptr;
    }
    // 分配足够空间存储所有word
    uint64\_t\* words = new uint64\_t\[wordCount\];
    // 调用napi\_get\_value\_bigint\_words接口获取传入bigInt相关信息，如：signBit传入bigInt正负信息
    status = napi\_get\_value\_bigint\_words(env, args\[0\], &signBit, &wordCount, words);
    OH\_LOG\_INFO(LOG\_APP, "Node-API , signBit: %{public}d.", signBit);
    if (status != napi\_ok) {
        OH\_LOG\_ERROR(LOG\_APP, "Node-API , reason:%{public}d.", status);
        delete\[\] words;
        napi\_throw\_error(env, nullptr, "napi\_get\_value\_bigint\_words fail");
        return nullptr;
    }
    // 可在此处处理words数组内容，如日志输出等
    // ...
    // 将符号位转化为int类型传出去
    napi\_value returnValue = nullptr;
    napi\_create\_int32(env, signBit, &returnValue);
    delete\[\] words;
    return returnValue;
}

接口声明

index.d.ts

export const getValueBigintWords: (bigIntWords: bigint) => bigint | undefined; // napi\_get\_value\_bigint\_words

ArkTS侧示例代码

// napi\_get\_value\_bigint\_words
let bigInt = BigInt(-5555555555555555);
let bigUint = BigInt(5555555555555555);
try {
  hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_value\_bigint\_words signBit is: %{public}d',
    testNapi.getValueBigintWords(bigInt));
  hilog.info(0x0000, 'testTag', 'Test Node-API napi\_get\_value\_bigint\_words signBit is: %{public}d',
    testNapi.getValueBigintWords(bigUint));
  // ...
} catch (error) {
  hilog.error(0x0000, 'testTag', 'Test Node-API NapiGetValueBigint: %{public}s', error.message);
  // ...
}

以上代码如果要在native cpp中打印日志，需在CMakeLists.txt文件中添加以下配置信息（并添加头文件：#include "hilog/log.h"）：

// CMakeLists.txt
add\_definitions( "-DLOG\_DOMAIN=0xd0d0" )
add\_definitions( "-DLOG\_TAG=\\"testTag\\"" )
target\_link\_libraries(entry PUBLIC libace\_napi.z.so libhilog\_ndk.z.so)