neon-bindings / neon Goto Github PK
View Code? Open in Web Editor NEWRust bindings for writing safe and fast native Node.js modules.
Home Page: https://www.neon-bindings.com/
License: Apache License 2.0
Rust bindings for writing safe and fast native Node.js modules.
Home Page: https://www.neon-bindings.com/
License: Apache License 2.0
Any plans for an async API? Any road blocks that you would anticipate?
Great module! Cheers.
The thread-local state tracking the current Isolate is probably going to be deprecated. The Isolate should be threaded through all methods calls from parameters that have access to it. In particular, it should be chained from the FunctionCallbackInfo
's info->GetIsolate()
method:
call.run(|scope| {
...
scope.array(...)
scope.object(...)
...
})
Implement the ability to call into a JS function from Rust.
In neon-sys there's a spurious compiler warning that's impossible to disable:
dherman$ cargo build
Compiling neon-sys v0.1.5 (file:///Users/dherman/Sources/neon/crates/neon-sys)
src/buffer.rs:10:38: 10:45 warning: found non-foreign-function-safe member in struct marked #[repr(C)]: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type, #[warn(improper_ctypes)] on by default
src/buffer.rs:10 pub fn data<'a, 'b>(out: &'a mut Buf<'b>, obj: Local);
^~~~~~~
I've informally confirmed with Rust team members that this is almost certainly a compiler bug, but we need to provide them with a minified test case.
I'm not crazy about the names nested
and chained
; they're named after the internal mechanism rather than the intended purpose.
For nested
I kind of like local
.
For chained
some options might be helper
or temporary
... something to suggest the predominant patterns of usage.
Not all neon-sys functions consistently place the outpointer in the first position, which is confusingly inconsistent.
Right now they're Nan_* and Node_* but that's not the level of abstraction being provided by this library.
The JsInteger type should expose a value()
method for returning its integer value. The value()
method of the Value
trait should probably change to as_value()
since it's probably pretty close to zero cost (depending on inlining heuristics it should be possible to get it to zero cost, I think). And then JsString::data()
should change to JsString::value()
for consistency.
Start building API docs with rustdoc and host them on gh-pages.
I was just installing something and had rust version 1.5, the module failed to install.
I updated to rust 1.7 and everything went okay.
We should investigate if it is possible for neon-cli (or something else) to warn the user that the module built with neon was tested with some rust version 1.x
Ref: https://docs.npmjs.com/files/package.json#engines
Sorry if this is the wrong place to file this.
This is not possible if value
is not an integer:
value.check::<JsInteger>().or(Ok(JsInteger::new(scope, 0)))
because the JsTypeError
will crash the program.
For safety, we need to guarantee that an escaping handle will escape into a stack that has a live handle scope. To enforce this, we can simply make the run
method a member method of Scope instead of a static:
scope.run(|innerScope| {
...
innerScope.escape(handle)
})
Followed the suggestion of using neon new to explore a simple hello world starter project. Running npm install, the post install step is failing due to an error from ld:
Compiling my-project v0.1.0 (file:///home/cmdln/src/git/my-project)
note: link against the following native artifacts when linking against this static library
note: the order and any duplication can be significant on some platforms, and so may need to be preserved
note: library: dl
note: library: pthread
note: library: gcc_s
note: library: rt
note: library: c
note: library: m
ACTION binding_gyp_my_project_target_shared_lib ../target/release/libmy_project.so
/usr/bin/ld: -f may not be used without -shared
collect2: error: ld returned 1 exit status
my_project.target.mk:26: recipe for target '../target/release/libmy_project.so' failed
make: *** [../target/release/libmy_project.so] Error 1
make: Leaving directory '/home/cmdln/src/git/my-project/build'
I'm a newbie to both Rust, and node-gyp but I found this project on twitter and thought it was pretty cool. I want to contribute to this repo and learn Rust too. So can you write a little "Hacking neon for dummies" guide to help newcomers like me get started? I just installed Rust, discovered Cargo, and am just checking out the code in this repo.
Thanks!
Just an FYI, but the name neon
has been around for a long while for this project: http://www.webdav.org/neon/ .
Hi,
i think we should use Result
as the return value for JsString::new
. That way we could 1. return a meaningful error 2. use try!
ps: im a rust noob, so sorry for that if there is a real reason against Result
The name Scope is possibly misleading -- it could confuse people into thinking it has something to do with JavaScript scope, as opposed to being a memory management scope in Rust. Worth thinking about alternative names.
There are some crufty neon-runtime
functions that aren't being used anymore; we should get rid of them.
Expose the arguments to the Call
API.
Implement an API for defining custom classes that extend existing classes. Some of the things this will require:
extends
clause in the class
macroClassDescriptor
variant for subclassesneon::DerivedClassMetadata
C++ class that extends neon::ClassMetadata
Would be great to be able to write:
array[0] = scope.integer(17);
and possibly even:
object["foo"] = scope.integer(42);
Need the ability to take a Local<Any>
and figure out which type of value it is.
This is a good starter bug: you should be able to copy what I did to add JsInteger::value() to add analogous methods to JsNumber and JsBoolean. You'll need to use the v8::Number and v8::Boolean APIs in the implementation.
The type definitions, especially for various object brands, involve a fair bit of boilerplate. This should be generated either from a macro or a build.rs
code generator.
Looking at the API docs makes it clear that the traits really want to have the names Value and Object. And I came up with the "SomeObject" nomenclature for the root of the Object type hierarchy. So there should be a consistent nomenclature for root types in the type hierarchy, like SomeValue and SomeObject. I'm not in love with Some- as the prefix, so maybe we can come up with something better.
Also, neon::buffer should get moved under neon::value. Should we mirror the type hierarchy in a module hierarchy? Like neon::value::object::{Array, Object} etc, and neon::value::object::typed_array::Uint8Array etc?
Publishing should depend on running cargo doc.
โ duplicate (why?); see #28 โ
Hi,
just a quick bug report - when creating a project with name that includes a minus, it will be put unsanitized into the source: some-project
will result in NODE_MODULE(some-project, __neon_main__);
Cheers
The v8::Value
predicates include IsInt32
and IsUint32
which suggests that maybe their value tagging scheme distinguishes the two? If so then there ought to be separate Int32
and Uint32
types. Need to investigate.
Some suggestions from @eddyb for making Scope objects more ergonomic:
API for throwing and catching exceptions.
To avoid people using unsafe raw pointers like v8::External or stashing pointers as integers in buffers, there should be a safe way to create custom objects that own a boxed pointer to a Rust data structure. Some constraints:
Pushing an update to crates.io requires the following manual steps:
RELEASES.md
.AUTHORS.md
to include any names of new contributors.neon
, neon-build
, and neon-runtime
crates (they are kept in lock-step at always the exact same major.minor.patch).Cargo.toml
dependency on neon-runtime
to the exact patch-level version of neon-runtime
.cargo update
in test/dynamic/native
.cargo clean && cargo update
in test/static
.cargo test
in the neon root directory and ensure the tests are green.cli/templates/Cargo.toml.hbs
dependencies on neon-build
and neon
to the exact patch-level version of neon
.cli/package.json
to the exact patch-level version of neon
.neon new
:
neon new smoke-test
in a temp directory.neon
dependency to { path = "<path/to/neon>" }
neon-build
build-dependency to { path = "<path/to/neon>/crates/neon-build" }
neon-cli
dependency in smoke-test/package.json
to <path/to/neon>/clinpm i
and node -e 'require(".")'
and see if it prints "hello node"
.v$major.$minor.$patch
.cli
and run npm publish
.crates/neon-build
and run cargo publish
. (Must be done before publishing neon
).crates/neon-runtime
and run cargo publish
. (Must be done before publishing neon
(next step)).cargo publish
.$major.$minor.$patch
and a release title of v$major.$minor.$patch
, and check the "This is a pre-release" checkbox and press "Publish release."I would like to automate as much of this as possible!
/cc @mmun
Since V8 actually allocates handles using the current isolate's innermost HandleScope, but the Rust types do not statically prevent attempting to allocate a handle connected to an outer Scope, dynamically track the linked list of Scopes and disallow allocation to a Scope that is not the current innermost one.
This seems unfortunate for performance, but I'm not sure if there's a faster way. Ideally we'd prevent it statically.
There should be an automated test that a vanilla project created by neon new
successfully compiles by just running the standard npm install
.
/cc @mmun
The PropertyName
trait is required by the Object
trait but not exported from the crate. This will become a hard error in a future version of Rust so it needs to be exported.
I originally didn't export the trait because I didn't want to allow new implementations of the trait, but I can just make it an unsafe trait.
The following code throws a JsTypeError
when trying to check
a property name, consisting entirely of digits, to a JsString
. So the following property names don't work: '0'
, '1351'
, '99'
, although they do work when cast to JsNumber
. As far as I know JS property names are always strings. It seems to happen when retrieving property names from get_own_property_names
.
var addon = require('../native');
console.log(addon.hello({ '55': undefined }));
#[macro_use]
extern crate neon;
use neon::vm::{Call, JsResult, Module};
use neon::js::{Value, Object, JsObject, JsString, JsNumber};
fn hello(call: Call) -> JsResult<JsString> {
let scope = call.scope;
let arguments = call.arguments;
let obj = try!(try!(arguments.require(scope, 0)).check::<JsObject>());
let names = try!(try!(obj.get_own_property_names(scope)).to_vec(scope));
for name in names {
try!(name.check::<JsString>()); // Type error
}
Ok(JsString::new(scope, "hello node").unwrap())
}
register_module!(m, {
m.export("hello", hello)
});
OS X El Capitan, and rustc 1.6.0-beta.3.
Should break the main library up into smaller modules.
If we think of storing locals as "updating" a scope, we can rationalize changing the APIs to take an &mut impl Scope
instead of an &impl Scope
. From there we can use the borrow checker rules to "freeze" a scope when we shadow it with .nested
and .chained
, which lets us enforce most of the invariants of v8's HandleScope
abstraction statically. For example:
realm.scoped(|outer| { // &mut impl Scope
let mut x = Integer::new(outer, 0); // Integer::new() takes an &mut outer
outer.nested(|_| { // .nested() takes a frozen &outer
x = Integer::new(outer, 666); // borrow error: outer is frozen
});
});
The only thing it doesn't prevent statically is shadowing a frozen scope:
realm.scoped(|outer| {
outer.nested(|_| { // .nested() takes a frozen &outer
outer.nested(|_| { // needs to be a dynamic error
// ...
});
});
});
The dynamic checks could be implemented with the same approach as today, but they would be rarer and possibly quite a bit less costly: instead of an extra branch on every creation of a local, they only have an extra branch on every shadowing of a scope.
One final thought: I wonder if this whole API is a fit for the future emplacement syntax.
For receiving and sending data from V8 through function invocation, are the parameters copied as well as the return object? I across the below article and thought it might be interesting if Neon support shared memory IO into V8.
http://blog.scottfrees.com/how-not-to-access-node-js-from-c-worker-threads
Implement the ability to create instances (as with new
) of custom classes from Rust.
In the neon
crate we can eliminate the dependence on node-gyp by making a macro analogous to the CPP NODE_MODULE
macro in Node. This would be a prerequisite to fulfilling the neon-cli RFC at neon-bindings/neon-cli#21. In PR #29 @eddyb showed how this could work.
(The node-sys
crate would continue to use node-gyp, since it requires C/C++ wrappers.)
We could create separate traits to namespace the different MOP operations, like
trait Own {
fn keys(&self) -> JS<Array>;
fn names(&self) -> JS<Array>;
}
But this would really be ideal ergonomically if there were a way to call methods with trait namespacing inline, like:
let names = obj.Own::names();
I'm not sure if such functionality is likely to happen, so if not, it might just be best to use method names all in the flat Object
trait.
This issue was automatically generated. Feel free to close without ceremony if
you do not agree with re-licensing or if it is not possible for other reasons.
Respond to @cmr with any questions or concerns, or pop over to
#rust-offtopic
on IRC to discuss.
You're receiving this because someone (perhaps the project maintainer)
published a crates.io package with the license as "MIT" xor "Apache-2.0" and
the repository field pointing here.
TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that
license is good for interoperation. The MIT license as an add-on can be nice
for GPLv2 projects to use your code.
The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.
Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.
To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright, due to not being a "creative
work", e.g. a typo fix) and then add the following to your README:
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.
and in your license headers, if you have them, use the following boilerplate
(based on that used in Rust):
// Copyright 2016 neon developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
It's commonly asked whether license headers are required. I'm not comfortable
making an official recommendation either way, but the Apache license
recommends it in their appendix on how to use the license.
Be sure to add the relevant LICENSE-{MIT,APACHE}
files. You can copy these
from the Rust repo for a plain-text
version.
And don't forget to update the license
metadata in your Cargo.toml
to:
license = "MIT/Apache-2.0"
I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!
To agree to relicensing, comment with :
I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.
Or, if you're a contributor, you can check the box in this repo next to your
name. My scripts will pick this exact phrase up and check your checkbox, but
I'll come through and manually review this issue later as well.
This Neon function reliably segfaults on both OS X and Linux:
fn test(call: Call) -> JsResult<JsValue> {
let scope = call.scope;
let arg = try!(call.arguments.require(scope, 0));
let obj = try!(arg.check::<JsObject>());
let foo = try!(obj.get(scope, "foo"));
let obj = try!(foo.check::<JsObject>());
obj.get(scope, 0)
}
when called with an object such as { foo: ["bar"] }
.
Reported on Slack by @msvbg -- thank you Martin!
Continuation of #47.
I think I can eliminate the 'fun
lifetime parameter to Scope
and just store the isolate pointer as an unsafe pointer. This should hopefully make elision more commonly applicable.
I'm running npm i
on a new neon project as well as the word count project and I am getting the following:
H:\Desktop\wc-demo-master>npm i
> [email protected] install H:\Desktop\wc-demo-master
> node-gyp rebuild
H:\Desktop\wc-demo-master>if not defined npm_config_node_gyp (node "C:\Users\Zach\AppData\Roaming\nvm\v4.2.3\node_modules\npm\bin\node-gyp-bin\\..\..\node_modules\node-gyp\bin\node-gyp.js" rebuild ) else (node rebuild )
File "<string>", line 1
'import
^
SyntaxError: EOL while scanning string literal
gyp: Call to 'python -c 'import os, json; print("" if u"--debug" in json.loads(os.getenv("npm_config_argv"))["cooked"] else "--release")'' returned exit status 1. while trying to load binding.gyp
I'm running Node v4.2.3 and Python2.7.10 - other native node modules build, which is odd because it partially seems like an issue with node-gyp as well as Python.
hi,
i try to compile the example from the readme:
#[macro_use]
extern crate neon;
use neon::vm::{Call, JsResult};
use neon::js::{JsString, JsArray, JsInteger, JsObject, JsNumber};
use neon::internal::js::{PropertyName};
fn make_an_array(call: Call) -> JsResult<JsArray> {
let scope = call.scope; // the current scope for rooting handles
let array = JsArray::new(scope, 3);
try!(array.set(0, JsInteger::new(scope, 9000)));
try!(array.set(1, JsObject::new(scope)));
try!(array.set(2, JsNumber::new(scope, 3.14159)));
Ok(array)
}
register_module!(m, {
m.export("main", make_an_array)
});
use neon::internal::js::{PropertyName};
looks fishy (no non-internal export; and causes more errors), but im getting without it:
src/lib.rs:20:13: 20:48 error: no method named `set` found for type `neon::internal::mem::Handle<'_, neon::internal::js::JsArray>` in the current scope
src/lib.rs:20 try!(array.set(0, JsInteger::new(scope, 9000)));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/lib.rs:20:2: 20:50 note: in this expansion of try! (defined in <std macros>)
src/lib.rs:20:13: 20:48 help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
src/lib.rs:20:13: 20:48 help: candidate #1: use `neon::internal::js::PropertyName`
[...]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.