Creating smart pointer via implement or extends from javascript

661 views
Skip to first unread message

ric...@snowcoders.com

unread,
May 1, 2016, 6:30:56 PM5/1/16
to emscripten-discuss
I've been investigating/playing with Embind and one of the things that currently bothers me is the allow_raw_pointers that I have in locations in my code. Essentially I'm using them in locations where I need the language specific resources to do some work. An example of this could be (but doesn't have to be through the use of Berkley sockets) if I wanted to use JQueries Ajax method to do requests.

The code is below if you want to see but basically we have a pure virtual class IAjaxAdapter and App. In it's constructor App takes a std::shared_ptr<IAjaxAdapter> but since IAjaxAdapter is created by running Module.IAjaxAdapter.implement or Module.IAjaxAdapter.extends, it creates a raw pointer, not a smart pointer and you eventually get the error "BindingError: Passing raw pointer to smart pointer is illegal" which makes complete sense.

So my question is if its possible to wrap or create a smart pointer when using implement or extends from the javascript side so you do not have to use allow_raw_pointers which would open up the internals of your code to possible abuse if those raw pointers are not handled correctly.

Cheers,
Ricky

ExternalImpl.h
#pragma once

#include <memory>
#include <string>
#include <map>

class IAjaxAdapter
{
public:
 
virtual void ajax(std::wstring url, std::map<std::wstring, std::wstring> settings) = 0;
};

class App
{
public:
 
App(std::shared_ptr<IAjaxAdapter> ajaxManager);
};


ExternalImpl.cpp
#include "ExternalImpl.h"

#ifdef EMSCRIPTEN
#include <emscripten/bind.h>

using namespace emscripten;
#endif

App::App(std::shared_ptr<IAjaxAdapter> ajaxManager)
{
 ajaxManager
->ajax(L"https://kripken.github.io", {});
}

#ifdef EMSCRIPTEN

struct IAjaxAdapterWrapper : public wrapper<IAjaxAdapter> {
 EMSCRIPTEN_WRAPPER
(IAjaxAdapterWrapper);
 
void ajax(std::wstring url, std::map<std::wstring, std::wstring> settings) {
 
return call<void>("ajax", url, settings);
 
}
};

EMSCRIPTEN_BINDINGS
(ExternalImpl) {
 class_
<IAjaxAdapter>("IAjaxAdapter")
 
.smart_ptr<std::shared_ptr<IAjaxAdapter>>("IAjaxAdapter")
 
.function("ajax", &IAjaxAdapter::ajax, pure_virtual())
 
.allow_subclass<IAjaxAdapterWrapper>("IAjaxAdapterWrapper")
 
;
 class_
<App>("App")
 
.smart_ptr_constructor("App", &std::make_shared<App, std::shared_ptr<IAjaxAdapter>>)
 
;
}
#endif


externalImpl.html
<HTML>
<HEAD>
   
<META NAME="GENERATOR" Content="Microsoft Visual Studio">
   
<TITLE></TITLE>
   
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.2.1.min.js" type="text/javascript"></script>
   
<script src="externalImpl.js" type="text/javascript"></script>
   
<script>
        $
(function () {
            $
("#writeToMe").text("Working");
           
var item = new Module.App(Module.IAjaxAdapter.implement({
                ajax
: function (url, settings) {
                    $
("#writeToMe").text('Ajax function called');
               
}
           
}));
       
});
   
</script>
</HEAD>
<BODY>
   
<div id="writeToMe"></div>
</BODY>
</HTML>


jymu...@gmail.com

unread,
Feb 3, 2019, 9:19:30 AM2/3/19
to emscripten-discuss
Hi Ricky,

I am having the same problem. Did you ever find a solution?

Ivan Romanovski

unread,
Feb 7, 2019, 5:59:51 AM2/7/19
to emscripten-discuss
I have managed to overcome this issue (creating a smart_ptr to a JS implementation of an abstract class defined in C++) using the following pattern: 

#include <emscripten/bind.h>
#include <emscripten.h>

class JSObserver : public Observer
{
public:
 JSObserver(emscripten::val callbacks) : myCallbacks(callbacks)  {}

  void onUpdate(const std::string &message)
 {
   emscripten::val onUpdateCB = myCallbacks["onUpdate"];
   onUpdateCB(message);
 }

private:
 emscripten::val myCallbacks;
};
} // namespace greetings

using namespace emscripten;
#ifdef __EMSCRIPTEN__
EMSCRIPTEN_BINDINGS(my_module)
{
 class_<Observer>("Observer")
     .smart_ptr<std::shared_ptr<Observer>>("Observer");
 class_<JSObserver, base<Observer>>("JSObserver")
     .smart_ptr_constructor("JSObserver", &std::make_shared<JSObserver, emscripten::val>);
}
#endif

See my GitHub for full example: https://github.com/IvanRomanovski/emscripten-examples/tree/master/observer-pattern
Reply all
Reply to author
Forward
0 new messages