Skip to content

Commit

Permalink
feat: Support arrays and objects in Kotlin AnyMap (#76)
Browse files Browse the repository at this point in the history
* feat: Create `JAnyValue`

* hmm

* Update JAnyMap.hpp

* Test it!

* fix registrations

* Format

* Update AnyMap.kt

* Update AnyMap.ts

* Update README.md

* downgrade ESLint

* fix: Fix lint
  • Loading branch information
mrousavy authored Aug 28, 2024
1 parent 64f071b commit 254967a
Show file tree
Hide file tree
Showing 23 changed files with 440 additions and 34 deletions.
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion example/babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ module.exports = {
},
],
],
};
}
8 changes: 4 additions & 4 deletions example/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AppRegistry } from 'react-native';
import App from './src/App';
import { name as appName } from './app.json';
import { AppRegistry } from 'react-native'
import App from './src/App'
import { name as appName } from './app.json'

AppRegistry.registerComponent(appName, () => App);
AppRegistry.registerComponent(appName, () => App)
2 changes: 1 addition & 1 deletion example/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module.exports = {
preset: 'react-native',
};
}
22 changes: 11 additions & 11 deletions example/metro.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const path = require('path');
const escape = require('escape-string-regexp');
const exclusionList = require('metro-config/src/defaults/exclusionList');
const pak = require('../package.json');
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config')
const path = require('path')
const escape = require('escape-string-regexp')
const exclusionList = require('metro-config/src/defaults/exclusionList')
const pak = require('../package.json')

const root = path.resolve(__dirname, '..');
const modules = Object.keys({ ...pak.peerDependencies });
const root = path.resolve(__dirname, '..')
const modules = Object.keys({ ...pak.peerDependencies })

/**
* Metro configuration
Expand All @@ -27,8 +27,8 @@ const config = {
),

extraNodeModules: modules.reduce((acc, name) => {
acc[name] = path.join(__dirname, 'node_modules', name);
return acc;
acc[name] = path.join(__dirname, 'node_modules', name)
return acc
}, {}),
},

Expand All @@ -40,6 +40,6 @@ const config = {
},
}),
},
};
}

module.exports = mergeConfig(getDefaultConfig(__dirname), config);
module.exports = mergeConfig(getDefaultConfig(__dirname), config)
3 changes: 2 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
"@types/deep-equal": "^1.0.4",
"babel-plugin-module-resolver": "^5.0.2",
"del-cli": "^5.1.0",
"eslint": "^9.9.1",
"eslint-config-prettier": "^9.1.0",
"eslint": "^8.57.0",
"eslint-plugin-prettier": "^5.2.1",
"nitro-codegen": "*",
"prettier": "^3.3.3",
Expand All @@ -46,6 +46,7 @@
"@react-native",
"prettier"
],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": [
"warn",
Expand Down
2 changes: 1 addition & 1 deletion example/react-native.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ module.exports = {
// root: path.join(__dirname, '..'),
// },
},
};
}
1 change: 1 addition & 0 deletions packages/nitrogen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"@react-native",
"prettier"
],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": [
"warn",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <jni.h>

#include "JFunc_void_std__string.hpp"
#include "JFunc_void_Person.hpp"
#include "JFunc_void_std__string.hpp"
#include "JHybridImageFactorySpec.hpp"
#include "JHybridImageSpec.hpp"
#include "JHybridKotlinTestObjectSpec.hpp"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.margelo.nitro.image

import com.margelo.nitro.core.AnyMap
import com.margelo.nitro.core.AnyValue
import com.margelo.nitro.core.ArrayBuffer
import com.margelo.nitro.core.Promise
import java.nio.ByteBuffer
Expand Down Expand Up @@ -34,6 +35,12 @@ class KotlinTestObject: HybridKotlinTestObjectSpec() {
map.setString("string", "String!")
map.setBoolean("bool", true)
map.setBigInt("bigint", 893256789)
map.setAnyObject("object", mapOf("first" to AnyValue(1), "second" to AnyValue("string"), "third" to AnyValue(
mapOf("nested" to AnyValue(true))
)))
map.setAnyArray("array", arrayOf(AnyValue(11), AnyValue(true), AnyValue(33.5), AnyValue("string"), AnyValue(
arrayOf(AnyValue("nested"), AnyValue(true))
)))
return map
}

Expand Down
1 change: 1 addition & 0 deletions packages/react-native-nitro-image/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"@react-native",
"prettier"
],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": [
"warn",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-native-nitro-modules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ The following C++ / JS types are supported out of the box:
<td><code>{ ... }</code></td>
<td><code>std::shared_ptr&lt;<a href="./cpp/core/AnyMap.hpp">AnyMap</a>&gt;</code></td>
<td><code><a href="./ios/core/AnyMapHolder.swift">AnyMapHolder</a></code> 🟡  (<a href="https://github.com/mrousavy/nitro/issues/57">#57</a>)</td>
<td><code><a href="./android/src/main/java/com/margelo/nitro/core/AnyMap.kt">AnyMap</a></code> 🟡  (<a href="https://github.com/mrousavy/nitro/issues/61">#61</a>)</td>
<td><code><a href="./android/src/main/java/com/margelo/nitro/core/AnyMap.kt">AnyMap</a></code></td>
</tr>
<tr>
<td><code>ArrayBuffer</code></td>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/// Entry point for JNI.

#include "JAnyMap.hpp"
#include "JAnyValue.hpp"
#include "JArrayBuffer.hpp"
#include "JHybridObjectRegistry.hpp"
#include "JPromise.hpp"
Expand All @@ -19,6 +20,7 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
JHybridObjectRegistry::registerNatives();
JArrayBuffer::registerNatives();
JAnyMap::registerNatives();
JAnyValue::registerNatives();
JPromise::registerNatives();
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,25 @@ using namespace facebook;
/**
* Represents an `ArrayBuffer` that holds a `ByteBuffer`.
*/
class ByteBufferArrayBuffer : public ArrayBuffer {
class ByteBufferArrayBuffer final : public ArrayBuffer {
public:
explicit ByteBufferArrayBuffer(jni::alias_ref<jni::JByteBuffer> byteBuffer) : _byteBuffer(jni::make_global(byteBuffer)) {
explicit ByteBufferArrayBuffer(const jni::alias_ref<jni::JByteBuffer>& byteBuffer) : _byteBuffer(jni::make_global(byteBuffer)) {
_byteBuffer->order(jni::JByteOrder::bigEndian());
}

public:
uint8_t* data() override {
[[nodiscard]] uint8_t* data() override {
return _byteBuffer->getDirectBytes();
}
size_t size() const override {
[[nodiscard]] size_t size() const override {
return _byteBuffer->getDirectSize();
}
bool isOwner() const noexcept override {
[[nodiscard]] bool isOwner() const noexcept override {
return _byteBuffer != nullptr && _byteBuffer->isDirect();
}

public:
jni::alias_ref<jni::JByteBuffer> getBuffer() const {
[[nodiscard]] jni::alias_ref<jni::JByteBuffer> getBuffer() const {
return _byteBuffer;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@
#pragma once

#include "AnyMap.hpp"
#include "JAnyValue.hpp"
#include <fbjni/fbjni.h>

namespace margelo::nitro {

using namespace facebook;

/**
* Represents a Promise implemented in Java.
* Represents an `AnyMap` implemented in Java.
*/
class JAnyMap : public jni::HybridClass<JAnyMap> {
class JAnyMap final : public jni::HybridClass<JAnyMap> {
public:
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/core/AnyMap;";

Expand Down Expand Up @@ -88,6 +89,25 @@ class JAnyMap : public jni::HybridClass<JAnyMap> {
std::string getString(const std::string& key) {
return _map->getString(key);
}
jni::alias_ref<JAnyArray> getAnyArray(const std::string& key) {
const auto& vector = _map->getArray(key);
auto javaArray = jni::JArrayClass<JAnyValue::javaobject>::newArray(vector.size());
for (size_t i = 0; i < vector.size(); i++) {
auto value = JAnyValue::create(vector[i]);
javaArray->setElement(i, value.get());
}
return javaArray;
}
jni::alias_ref<JAnyObject> getAnyObject(const std::string& key) {
const auto& map = _map->getObject(key);
auto javaMap = jni::JHashMap<jni::JString, JAnyValue::javaobject>::create(map.size());
for (const auto& entry : map) {
auto string = jni::make_jstring(entry.first);
auto value = JAnyValue::create(entry.second);
javaMap->put(string, value);
}
return javaMap;
}

protected:
void setNull(const std::string& key) {
Expand All @@ -105,6 +125,24 @@ class JAnyMap : public jni::HybridClass<JAnyMap> {
void setString(const std::string& key, const std::string& value) {
_map->setString(key, value);
}
void setAnyArray(const std::string& key, jni::alias_ref<JAnyArray> value) {
std::vector<AnyValue> vector;
size_t size = value->size();
vector.reserve(size);
for (size_t i = 0; i < size; i++) {
auto anyValue = value->getElement(i);
vector.push_back(anyValue->cthis()->getValue());
}
_map->setArray(key, vector);
}
void setAnyObject(const std::string& key, const jni::alias_ref<JAnyObject>& value) {
std::unordered_map<std::string, AnyValue> map;
map.reserve(value->size());
for (const auto& entry : *value) {
map.emplace(entry.first->toStdString(), entry.second->cthis()->getValue());
}
_map->setObject(key, map);
}

public:
std::shared_ptr<AnyMap> getMap() const {
Expand Down Expand Up @@ -138,12 +176,16 @@ class JAnyMap : public jni::HybridClass<JAnyMap> {
makeNativeMethod("getBoolean", JAnyMap::getBoolean),
makeNativeMethod("getBigInt", JAnyMap::getBigInt),
makeNativeMethod("getString", JAnyMap::getString),
makeNativeMethod("getAnyArray", JAnyMap::getAnyArray),
makeNativeMethod("getAnyObject", JAnyMap::getAnyObject),
// set
makeNativeMethod("setNull", JAnyMap::setNull),
makeNativeMethod("setDouble", JAnyMap::setDouble),
makeNativeMethod("setBoolean", JAnyMap::setBoolean),
makeNativeMethod("setBigInt", JAnyMap::setBigInt),
makeNativeMethod("setString", JAnyMap::setString),
makeNativeMethod("setAnyArray", JAnyMap::setAnyArray),
makeNativeMethod("setAnyObject", JAnyMap::setAnyObject),
});
}
};
Expand Down
Loading

0 comments on commit 254967a

Please sign in to comment.