first version

This commit is contained in:
Jay 2020-08-25 11:10:05 +08:00
parent ad2ba7b3da
commit 7ec4de3192
8 changed files with 3379 additions and 53 deletions

1
.gitignore vendored
View File

@ -120,3 +120,4 @@ dist
Cargo.lock Cargo.lock
*.node *.node
.idea

View File

@ -1,7 +1,7 @@
[package] [package]
name = "napi-package-template" name = "node-rs-diff"
version = "0.1.0" version = "0.1.0"
authors = ["LongYinan <lynweklm@gmail.com>"] authors = ["Jay <jay@trj.tw>"]
edition = "2018" edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -10,6 +10,7 @@ edition = "2018"
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
diff = "0.1.12"
napi = { version = "0.4" } napi = { version = "0.4" }
napi-derive = { version = "0.4" } napi-derive = { version = "0.4" }

View File

@ -1,14 +1,11 @@
const test = require('ava') const test = require('ava')
const { sleep, sync } = require('../index') const { diff } = require('../index')
test('sync function from native code', (t) => { test('diff', (t) => {
const fixture = 42 const left = 'asd'
t.is(sync(fixture), fixture + 100) const right = 'asd'
}) const result = diff(left, right)
console.log(result)
test('sleep function from native code', async (t) => { t.is(result.length, 1)
const timeToSleep = 200
const value = await sleep(timeToSleep)
t.is(value, timeToSleep * 2)
}) })

4
index.d.ts vendored
View File

@ -1,3 +1 @@
export const sync: (input: number) => number export const diff: (left: string, right: string) => []
// sleep [duration] ms, return Promise which resolved 2 * duration
export const sleep: (duration: number) => Promise<number>

3268
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
{ {
"name": "@napi-rs/package-template", "name": "rs-diff",
"version": "0.0.6", "version": "0.0.1",
"description": "Template project for writing node package with napi-rs", "description": "Template project for writing node package with napi-rs",
"main": "index.js", "main": "index.js",
"repository": "git@github.com:napi-rs/package-template.git", "repository": "https://git.trj.tw/nodejs/rs-diff.git",
"license": "MIT", "license": "MIT",
"keywords": ["napi-rs", "NAPI", "N-API", "Rust", "node-addon", "node-addon-api"], "keywords": ["napi-rs", "NAPI", "N-API", "Rust", "node-addon", "node-addon-api"],
"files": ["index.d.ts", "index.js"], "files": ["index.d.ts", "index.js"],
@ -13,12 +13,12 @@
"node": ">= 8.9" "node": ">= 8.9"
}, },
"publishConfig": { "publishConfig": {
"registry": "https://registry.npmjs.org/", "registry": "https://npm.trj.tw",
"access": "public" "access": "public"
}, },
"scripts": { "scripts": {
"build": "cargo build --release && napi --platform --release ./index", "build": "cargo build --release && napi build --platform --release ./index",
"build:debug": "cargo build && napi --platform ./index", "build:debug": "cargo build && napi build --platform ./index",
"prepublishOnly": "node ./scripts/publish.js", "prepublishOnly": "node ./scripts/publish.js",
"test": "ava", "test": "ava",
"version": "node ./scripts/version.js" "version": "node ./scripts/version.js"

View File

@ -5,7 +5,9 @@ extern crate napi_derive;
use std::convert::TryInto; use std::convert::TryInto;
use napi::{CallContext, Env, JsNumber, JsObject, Module, Result, Task}; use napi::{CallContext, Env, JsNumber, JsObject, JsString, Module, Result, Task};
mod mdiff;
#[cfg(all(unix, not(target_env = "musl")))] #[cfg(all(unix, not(target_env = "musl")))]
#[global_allocator] #[global_allocator]
@ -13,41 +15,34 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
register_module!(example, init); register_module!(example, init);
struct AsyncTask(u32);
impl Task for AsyncTask {
type Output = u32;
type JsValue = JsNumber;
fn compute(&mut self) -> Result<Self::Output> {
use std::thread::sleep;
use std::time::Duration;
sleep(Duration::from_millis(self.0 as u64));
Ok(self.0 * 2)
}
fn resolve(&self, env: &mut Env, output: Self::Output) -> Result<Self::JsValue> {
env.create_uint32(output)
}
}
fn init(module: &mut Module) -> Result<()> { fn init(module: &mut Module) -> Result<()> {
module.create_named_method("sync", sync_fn)?; module.create_named_method("diff", diff_char)?;
module.create_named_method("sleep", sleep)?;
Ok(()) Ok(())
} }
#[js_function(1)] #[js_function(2)]
fn sync_fn(ctx: CallContext) -> Result<JsNumber> { fn diff_char(ctx: CallContext) -> Result<JsObject> {
let argument: u32 = ctx.get::<JsNumber>(0)?.try_into()?; let str1: String = ctx.get::<JsString>(0)?.try_into()?;
let str2: String = ctx.get::<JsString>(1)?.try_into()?;
ctx.env.create_uint32(argument + 100) let res = mdiff::diff_chars(str1.as_str(), str2.as_str());
}
#[js_function(1)] let mut obj = ctx.env.create_array_with_length(res.len()).unwrap();
fn sleep(ctx: CallContext) -> Result<JsObject> {
let argument: u32 = ctx.get::<JsNumber>(0)?.try_into()?; let mut idx = 0;
let task = AsyncTask(argument); for it in res.iter() {
ctx.env.spawn(task) let mut item = ctx.env.create_object().unwrap();
item.set_named_property(
"count",
ctx.env.create_int64(it.count.try_into().unwrap()).unwrap(),
);
item.set_named_property("value", ctx.env.create_string(&it.value).unwrap());
item.set_named_property("added", ctx.env.get_boolean(it.added).unwrap());
item.set_named_property("removed", ctx.env.get_boolean(it.removed).unwrap());
obj.set_index(idx, item);
idx += 1;
}
Ok(obj)
} }

66
src/mdiff.rs Normal file
View File

@ -0,0 +1,66 @@
pub struct Res {
pub count: usize,
pub added: bool,
pub removed: bool,
pub value: String,
}
#[derive(PartialEq, Debug)]
pub enum Mode {
INIT,
BOTH,
LEFT,
RIGHT,
}
fn get_res(s: &String, mode: Mode) -> Res {
Res {
count: s.chars().count(),
added: if mode == Mode::RIGHT { true } else { false },
removed: if mode == Mode::LEFT { true } else { false },
value: s.clone(),
}
}
pub fn diff_chars(s1: &str, s2: &str) -> Vec<Res> {
let mut mode = Mode::INIT;
let mut s: String = String::new();
let mut result: Vec<Res> = Vec::new();
for d in diff::chars(s1, s2) {
match d {
diff::Result::Left(l) => {
if mode != Mode::LEFT && mode != Mode::INIT {
result.push(get_res(&s, mode));
s.clear();
}
mode = Mode::LEFT;
s.push(l);
}
diff::Result::Right(r) => {
if mode != Mode::RIGHT && mode != Mode::INIT {
result.push(get_res(&s, mode));
s.clear();
}
mode = Mode::RIGHT;
s.push(r);
}
diff::Result::Both(l, _) => {
if mode != Mode::BOTH && mode != Mode::INIT {
result.push(get_res(&s, mode));
s.clear();
}
mode = Mode::BOTH;
s.push(l);
}
}
}
if s.len() > 0 {
result.push(get_res(&s, mode));
s.clear();
}
result
}