Skip to content

Commit

Permalink
Basic WASM POC showing CDF variables count
Browse files Browse the repository at this point in the history
Signed-off-by: Alexis Jeandet <alexis.jeandet@member.fsf.org>
  • Loading branch information
jeandet committed Jan 11, 2024
1 parent c1b4d45 commit 7f5a8c2
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 6 deletions.
11 changes: 6 additions & 5 deletions include/cdfpp/cdf-io/loading/records-loading.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct parsing_context_t
}
};

SPLIT_FIELDS_FW_DECL(std::size_t, load_record,);
SPLIT_FIELDS_FW_DECL(std::size_t, load_record, );

template <typename record_t, typename parsing_context_t, typename T>
inline std::size_t load_field(
Expand Down Expand Up @@ -135,7 +135,7 @@ inline std::size_t load_fields(const record_t& r, parsing_context_t& parsing_con
return load_fields(r, parsing_context, offset, std::forward<Ts>(fields)...);
}

SPLIT_FIELDS(std::size_t, load_record, load_fields,);
SPLIT_FIELDS(std::size_t, load_record, load_fields, );


template <typename version_t>
Expand Down Expand Up @@ -289,7 +289,7 @@ auto begin_AgrEDR(const cdf_ADR_t<version_t>& adr, buffer_t& buffer)
{
using aedr_t = cdf_AgrEDR_t<version_t>;

return blk_iterator<aedr_t, buffer_t> { adr.AgrEDRhead, buffer,
return blk_iterator<aedr_t, buffer_t> { static_cast<std::size_t>(adr.AgrEDRhead), buffer,
[](const aedr_t& aedr) { return aedr.AEDRnext; } };
}

Expand All @@ -305,7 +305,7 @@ auto begin_AzEDR(const cdf_ADR_t<version_t>& adr, buffer_t& buffer)
{
using aedr_t = cdf_AzEDR_t<version_t>;

return blk_iterator<aedr_t, buffer_t> { adr.AzEDRhead, buffer,
return blk_iterator<aedr_t, buffer_t> { static_cast<std::size_t>(adr.AzEDRhead), buffer,
[](const aedr_t& aedr) { return aedr.AEDRnext; } };
}

Expand Down Expand Up @@ -351,7 +351,8 @@ auto begin_VDR(parsing_context_t& parsing_context)
else if constexpr (type == cdf_r_z::z)
{
using vdr_t = cdf_zVDR_t<version_t>;
return blk_iterator<vdr_t, parsing_context_t> { parsing_context.gdr.zVDRhead,
return blk_iterator<vdr_t, parsing_context_t> { static_cast<std::size_t>(
parsing_context.gdr.zVDRhead),
parsing_context, [](const vdr_t& vdr) { return vdr.VDRnext; } };
}
}
Expand Down
5 changes: 4 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
project(
'pycdfpp',
'cpp','c',
meson_version: '>= 0.63.0',
meson_version: '>= 0.64.0',
version : run_command('scripts/version.py',
capture:true,
env:{'SRC_ROOT':meson.project_source_root()}
Expand Down Expand Up @@ -226,6 +226,9 @@ install_headers(
], subdir:'cdfpp/cdf-io/saving')


subdir('wacdfpp')


if get_option('with_tests')

configure_file(output : 'tests_config.hpp',
Expand Down
22 changes: 22 additions & 0 deletions wacdfpp/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
fs = import('fs')


flags = ['-sWASM=2', '-sALLOW_MEMORY_GROWTH', '-sFETCH=1', '-sASYNCIFY']+['-sWASM=2', '-sEXPORT_ALL=1', '-sMODULARIZE', '-sEXPORTED_RUNTIME_METHODS=ccall', '-lembind', '-sFETCH=1', '--bind', '-sALLOW_MEMORY_GROWTH']

lib_wacdfpp = library('wacdfpp', 'wacdfpp.cpp',
dependencies:[cdfpp_dep],
cpp_args : flags,
install: false,
link_args : flags,
build_by_default: meson.get_compiler('cpp').get_id() == 'emscripten',
extra_files : ['wasm.txt', 'wacdfpp.html']
)

js_wrapper = custom_target('js_wrapper',
input : lib_wacdfpp,
output : 'wacdfpp.js',
command : [ 'emcc', '-lembind', '-sFETCH=1', '-sWASM=2', '--bind', '-sALLOW_MEMORY_GROWTH', '-sASYNCIFY', '-o', '@OUTPUT@', '-Wl,--whole-archive','@INPUT@', '-Wl,--no-whole-archive'],
build_by_default: true
)

fs.copyfile('wacdfpp.html', 'wacdfpp.html')
72 changes: 72 additions & 0 deletions wacdfpp/wacdfpp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include <cdfpp/cdf.hpp>
#include <filesystem>
#include <iostream>
#include <string>
#include <vector>
#if __has_include(<emscripten.h>)
#include <emscripten.h>
#include <emscripten/bind.h>
#include <emscripten/fetch.h>
#else
#define EMSCRIPTEN_KEEPALIVE
#define EMSCRIPTEN_EXPORT(x) x
#endif


EMSCRIPTEN_KEEPALIVE
emscripten::val count_variables(std::string url)
{
struct fetch_data
{
bool done = false;
std::vector<char> data;
};
emscripten_fetch_attr_t attr;
emscripten_fetch_attr_init(&attr);
strcpy(attr.requestMethod, "GET");
attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
attr.userData = new fetch_data;
attr.onsuccess = [](emscripten_fetch_t* fetch)
{
auto data = static_cast<fetch_data*>(fetch->userData);
data->data = std::vector<char>(fetch->data, fetch->data + fetch->numBytes);
data->done = true;
emscripten_fetch_close(fetch);
};
attr.onerror = [](emscripten_fetch_t* fetch)
{
auto data = static_cast<fetch_data*>(fetch->userData);
data->done = true;
emscripten_fetch_close(fetch);
};
emscripten_fetch(&attr, url.c_str());
while (!static_cast<fetch_data*>(attr.userData)->done)
{
emscripten_sleep(10);
}
auto data = static_cast<fetch_data*>(attr.userData);
if (auto cdf_file = cdf::io::load(data->data); cdf_file)
{
std::cout << "Variables: " << std::size(cdf_file->variables) << "\n";
auto sz = std::size(cdf_file->variables);
delete data;
return emscripten::val(sz);
}
return emscripten::val(-1);
}


EMSCRIPTEN_KEEPALIVE
int my_cdf_test()
{
return 42;
}


#ifdef __EMSCRIPTEN__
EMSCRIPTEN_BINDINGS(cdfppjs)
{
emscripten::function("my_cdf_test", &my_cdf_test);
emscripten::function("count_variables", &count_variables);
}
#endif
48 changes: 48 additions & 0 deletions wacdfpp/wacdfpp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<!doctype html>
<html>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
<div id="container">
<p>
<input type="text" id="URL" name="URL" />
<input id="myButton" type=button value="Read CDF">
<output name="result" id="count"/>
</p>
</div>
<script>

console.log("loading wasm");

var Module = {
canvas: (function() {
var canvas = document.getElementById('canvas');
return canvas;
})(),

onRuntimeInitialized: function() {
console.log("wasm loaded");
console.log("wasm initialized");
}
};
</script>
<script src="wacdfpp.js"></script>

<script>
function callback() {
const URL = document.getElementById("URL").value;

// Disable the button while the operation is in progress
document.getElementById("myButton").disabled = true;

// Fetch the data and process it asynchronously
Module.count_variables(URL).then(function(count) {
// Update the count and enable the button when processing is done
document.getElementById("count").innerHTML = count;
document.getElementById("myButton").disabled = false;
});
}

myButton.addEventListener('click', callback);
</script>
</body>
</html>
23 changes: 23 additions & 0 deletions wacdfpp/wasm.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[binaries]
c = 'emcc'
cpp = 'em++'
ar = 'emar'
exe_wrapper = 'node'

[built-in options]
c_args = []
c_link_args = ['-sEXPORT_ALL=1', '-sWASM=2', '-sMODULARIZE', '-sEXPORTED_RUNTIME_METHODS=ccall']
cpp_args = []
cpp_link_args = []


[properties]
# Emscripten always needs an exe wrapper. Again,
# maybe Meson could just know this.
needs_exe_wrapper = true

[host_machine]
system = 'wasm'
cpu_family = 'wasm'
cpu = 'wasm'
endian = 'little'

0 comments on commit 7f5a8c2

Please sign in to comment.