Skip to content

Commit

Permalink
feat(Functions): nested js functions
Browse files Browse the repository at this point in the history
  • Loading branch information
BotellaA committed Aug 26, 2021
1 parent f8cb0cd commit 9262f6e
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:

strategy:
matrix:
node-version: [10.x, 12.x]
node-version: [12.x, 14.x]
os: [ubuntu-latest, windows-latest, macos-latest]

steps:
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ var example = require('bindings')('my-genepi-addon');
Functions not belonging to any class can be exported inside a named or an anonymous namespace.
The C++ function gets exported to JavaScript with the same name using `GENEPI_FUNCTION`,
or it can be renamed by adding a second argument (without quotation marks) using `NAMED_GENEPI_FUNCTION`.
Addind double underscore in the new name will result in adding the function in nested objects on the js side.

If the C++ function is overloaded, `GENEPI_MULTIFUNCTION` macro must be used
instead. See [overloaded functions](#overloaded-functions).
Expand All @@ -189,6 +190,11 @@ void sayBye( const std::string& name )
std::cout << "Bye, " << name << std::endl;
}

void sayByeAgain( const std::string& name )
{
std::cout << "Bye again, " << name << std::endl;
}

namespace foo
{
void sayNamespacedHello( const std::string& name )
Expand All @@ -203,6 +209,7 @@ namespace
{
GENEPI_FUNCTION( sayHello );
NAMED_GENEPI_FUNCTION( sayBye, sayGoodbye );
NAMED_GENEPI_FUNCTION( sayByeAgain, say__Goodbye );
}

namespace foo
Expand All @@ -220,6 +227,7 @@ var functions = require('genepi-functions.node');
functions.sayHello('you'); // Output: Hello, you
functions.sayGoodbye('you'); // Output: Bye, you
functions.say.Goodbye('you'); // Output: Bye again, you
functions.sayNamespacedHello('you'); // Output: Hello, you
```

Expand Down
6 changes: 6 additions & 0 deletions examples/functions/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ void sayBye( const std::string& name )
std::cout << "Bye, " << name << std::endl;
}

void sayBye2( const std::string& name )
{
std::cout << "Bye2, " << name << std::endl;
}

void displayArray( std::vector< double > values )
{
for( const auto i : values )
Expand Down Expand Up @@ -67,6 +72,7 @@ namespace
{
GENEPI_FUNCTION( sayHello );
NAMED_GENEPI_FUNCTION( sayBye, sayGoodbye );
NAMED_GENEPI_FUNCTION( sayBye2, say__Goodbye );
GENEPI_FUNCTION( displayArray );
GENEPI_FUNCTION( displayArray2 );
} // namespace
Expand Down
1 change: 1 addition & 0 deletions examples/functions/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var functions = require('bindings')('genepi-functions');

functions.sayHello('you');
functions.sayGoodbye('you');
functions.say.Goodbye('you');
functions.sayNamespacedHello('you');

const array = [1, 2, 3]
Expand Down
5 changes: 0 additions & 5 deletions include/genepi/bind_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ namespace genepi

void initialize( Napi::Env& env, Napi::Object& target ) final
{
if( is_initialized_ )
{
return;
}
is_initialized_ = true;
std::deque< MethodDefinition > methods;
std::unordered_set< const BindClassBase* > classes;
initialize_api( methods, classes );
Expand Down
1 change: 0 additions & 1 deletion include/genepi/bind_class_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ namespace genepi
}

protected:
bool is_initialized_{ false };
std::string name_;
std::map< unsigned int, std::vector< Callable > > constructors_;
std::deque< MethodDefinition > static_methods_;
Expand Down
57 changes: 49 additions & 8 deletions include/genepi/function_definition.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,63 @@ namespace genepi

void initialize( Napi::Env& env, Napi::Object& exports )
{
if( is_initialized_ )
{
return;
}
is_initialized_ = true;
auto param = new genepi::SignatureParam;
param->method_number = number();
exports.Set( Napi::String::New( env, name() ),
export_path( name(),
Napi::Function::New( env, signature()->caller(), "",
static_cast< void* >(
Napi::External< genepi::SignatureParam >::New(
env, param )
.Data() ) ) );
.Data() ) ),
exports );
}

private:
bool is_initialized_{ false };
void export_path(
const std::string& path, Napi::Value value, Napi::Object obj )
{
auto last_object = obj;
const auto tokens = split( path );
for( auto i = 0; i != tokens.size() - 1; i++ )
{
const auto& property = tokens[i];
Napi::Value prop_value = last_object.Get( property );
if( prop_value.IsObject() )
{
last_object = prop_value.As< Napi::Object >();
}
else if( prop_value.IsUndefined() )
{
auto new_object = Napi::Object::New( obj.Env() );
last_object.DefineProperty( Napi::PropertyDescriptor::Value(
property, new_object, napi_default_jsproperty ) );
last_object = new_object;
}
else
{
throw Napi::Error::New(
obj.Env(), "Attempted to set property \"" + property
+ "\" on a non-object" );
}
}
last_object.DefineProperty( Napi::PropertyDescriptor::Value(
tokens.back(), value, napi_default_jsproperty ) );
}

std::vector< std::string > split( const std::string& s )
{
std::vector< std::string > output;
std::string::size_type prev_pos = 0, pos = 0;
while( ( pos = s.find( "__", pos ) ) != std::string::npos )
{
std::string substring( s.substr( prev_pos, pos - prev_pos ) );
output.push_back( substring );
pos += 2;
prev_pos = pos;
}
output.push_back(
s.substr( prev_pos, pos - prev_pos ) ); // Last word
return output;
}
};
} // namespace genepi

0 comments on commit 9262f6e

Please sign in to comment.