mirror of
https://github.com/enso-org/enso.git
synced 2024-11-27 06:32:30 +03:00
parent
bc410b6d52
commit
43f51e9dac
12
ide/gui/.gitignore
vendored
12
ide/gui/.gitignore
vendored
@ -1,12 +0,0 @@
|
|||||||
# Rust
|
|
||||||
/target
|
|
||||||
**/*.rs.bk
|
|
||||||
Cargo.lock
|
|
||||||
bin/
|
|
||||||
pkg/
|
|
||||||
wasm-pack.log
|
|
||||||
|
|
||||||
# IntelliJ
|
|
||||||
.idea/
|
|
||||||
.vscode/
|
|
||||||
*.iml
|
|
@ -1,44 +0,0 @@
|
|||||||
unstable_features = true
|
|
||||||
required_version = "1.4.8"
|
|
||||||
|
|
||||||
# Basic Configuration
|
|
||||||
edition = "2018"
|
|
||||||
newline_style = "Unix"
|
|
||||||
format_code_in_doc_comments = true
|
|
||||||
format_macro_matchers = true
|
|
||||||
use_field_init_shorthand = true
|
|
||||||
use_small_heuristics = "Max"
|
|
||||||
use_try_shorthand = true
|
|
||||||
where_single_line = true
|
|
||||||
condense_wildcard_suffixes = true # `let (a,b,_,_) = x` -> `let (a,b,..) = x`
|
|
||||||
|
|
||||||
# Max Width
|
|
||||||
max_width = 80
|
|
||||||
error_on_line_overflow = true
|
|
||||||
error_on_unformatted = true
|
|
||||||
format_strings = true
|
|
||||||
wrap_comments = true
|
|
||||||
|
|
||||||
# Comments
|
|
||||||
normalize_comments = true
|
|
||||||
normalize_doc_attributes = true
|
|
||||||
|
|
||||||
# Imports
|
|
||||||
#merge_imports = true
|
|
||||||
|
|
||||||
|
|
||||||
# Newlines
|
|
||||||
overflow_delimited_expr = true
|
|
||||||
|
|
||||||
# Ordering
|
|
||||||
reorder_impl_items = true
|
|
||||||
|
|
||||||
# Vertical Alignment
|
|
||||||
struct_field_align_threshold = 80
|
|
||||||
enum_discrim_align_threshold = 80
|
|
||||||
spaces_around_ranges = true
|
|
||||||
brace_style = "PreferSameLine"
|
|
||||||
|
|
||||||
# Reporting
|
|
||||||
report_fixme = "Unnumbered"
|
|
||||||
report_todo = "Unnumbered"
|
|
@ -1,10 +0,0 @@
|
|||||||
[workspace]
|
|
||||||
|
|
||||||
members = [
|
|
||||||
"lib/core",
|
|
||||||
"lib/structology/core",
|
|
||||||
"lib/structology/macros",
|
|
||||||
]
|
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
opt-level = 3
|
|
@ -1,21 +0,0 @@
|
|||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2019 Luna Team, Inc. http://luna-lang.org
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
@ -1,75 +0,0 @@
|
|||||||
[![License](https://img.shields.io/static/v1?label=License&message=MIT&color=2ec352&labelColor=2c3239)](https://github.com/luna/basegl/blob/master/LICENSE) [![Actions Status](https://github.com/luna/basegl/workflows/Build%20%28MacOS%2C%20Linux%2C%20Windows%29/badge.svg)](https://github.com/luna/basegl/actions) [![Coverage](https://img.shields.io/codecov/c/github/luna/basegl?label=Coverage&labelColor=2c3239)](https://codecov.io/gh/luna/basegl/branch/master)
|
|
||||||
![Stability](https://img.shields.io/static/v1?label=Stability&message=Unstable&color=d52229&labelColor=2c3239)
|
|
||||||
|
|
||||||
# BaseGL
|
|
||||||
|
|
||||||
BaseGL is a blazing fast 2D drawing API. This repository is a work in progress
|
|
||||||
of BaseGL 2.0. Please refer to BaseGL 1.0 repository for more information:
|
|
||||||
https://github.com/luna/basegl-old.
|
|
||||||
|
|
||||||
## Working with the code
|
|
||||||
|
|
||||||
### The Rust toolchain
|
|
||||||
|
|
||||||
In order to use some of the WASM pipeline features we need to use a nightly Rust
|
|
||||||
channel. The same applies to the code auto-formatter and it's advanced
|
|
||||||
configuration options used here. You would neither be able to compile not format
|
|
||||||
the code using the stable branch.
|
|
||||||
|
|
||||||
To setup the toolchain, please use the [the Rust toolchain installer
|
|
||||||
](https://rustup.rs/):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rustup toolchain install nightly-2019-10-03 # Install the nightly channel.
|
|
||||||
rustup default nightly # Set it as the default one.
|
|
||||||
rustup component add rustfmt # Install the code auto-formatter.
|
|
||||||
rustup component add clippy # Install the linter.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Building and testing the project
|
|
||||||
|
|
||||||
Please use the `script/build.sh`, `script/watch.sh`, and `script/lint.sh`
|
|
||||||
scripts to build, watch, and lint the project respectively. We need to use a
|
|
||||||
simple custom wrappers here because of the several Rust toolchain issues:
|
|
||||||
|
|
||||||
- [No direct support for Cargo Workspaces in
|
|
||||||
wasm-pack.](https://github.com/rustwasm/wasm-pack/issues/642). Fixed in
|
|
||||||
`build.sh`.
|
|
||||||
- There is no watch utility in wasm-pack, which makes using it harder than it
|
|
||||||
should be. Fixed in `watch.sh`.
|
|
||||||
- [The commands cargo-check and cargo-clippy do not clean local cache if used
|
|
||||||
several times.](https://github.com/rust-lang/cargo/issues/6986). Fixed in
|
|
||||||
`lint.sh`.
|
|
||||||
|
|
||||||
In order to build an example demo scene, please use the following commands:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./script/watch.sh # Build and watch for changes.
|
|
||||||
|
|
||||||
# Wait till the project finishes building.
|
|
||||||
# Run the following lines from other cmd:
|
|
||||||
|
|
||||||
cd examples/01-scene
|
|
||||||
npm install
|
|
||||||
npm run start
|
|
||||||
```
|
|
||||||
|
|
||||||
You can now open the following address in your browser: http://localhost:8080.
|
|
||||||
**Please remember to disable the cache in your browser!**
|
|
||||||
|
|
||||||
### Working with the source code
|
|
||||||
|
|
||||||
#### Formatting
|
|
||||||
|
|
||||||
All codebase should be auto-formatted using `rustfmt`. It is highly recommended
|
|
||||||
that you use an IDE which takes care of formatting the code as you type. Please
|
|
||||||
remember that auto-formatting does not mean you should not care of the way your
|
|
||||||
code looks and feels! Be sure to carefully read the [Rust style
|
|
||||||
guide](https://github.com/luna/enso/blob/master/doc/rust-style-guide.md) and
|
|
||||||
apply it everywhere in your codebase.
|
|
||||||
|
|
||||||
|
|
||||||
#### Linting
|
|
||||||
|
|
||||||
Please be sure to fix all errors reported by `cargo clippy` before creating a
|
|
||||||
pull request to this repository.
|
|
2
ide/gui/examples/01-scene/.gitignore
vendored
2
ide/gui/examples/01-scene/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
node_modules
|
|
||||||
dist
|
|
5
ide/gui/examples/01-scene/bootstrap.js
vendored
5
ide/gui/examples/01-scene/bootstrap.js
vendored
@ -1,5 +0,0 @@
|
|||||||
// A dependency graph that contains any wasm must all be imported
|
|
||||||
// asynchronously. This `bootstrap.js` file does the single async import, so
|
|
||||||
// that no one else needs to worry about it again.
|
|
||||||
import("./index.js")
|
|
||||||
.catch(e => console.error("Error importing `index.js`:", e));
|
|
@ -1,19 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
|
||||||
<title>BaseGL Example</title>
|
|
||||||
<style>
|
|
||||||
html, body { width:100vw; height:100vh; }
|
|
||||||
body { margin:0; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
|
|
||||||
<div id="app" style="height:100vh; width:100vw; display:block">
|
|
||||||
<canvas id="canvas" style="height:100vh; width:100vw; display:block"></canvas>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
<script src="./bootstrap.js"></script>
|
|
||||||
</html>
|
|
@ -1 +0,0 @@
|
|||||||
import * as wasm from "basegl";
|
|
6058
ide/gui/examples/01-scene/package-lock.json
generated
6058
ide/gui/examples/01-scene/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "example-scene",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"description": "Example Scene",
|
|
||||||
"main": "index.js",
|
|
||||||
"bin": {
|
|
||||||
"create-wasm-app": ".bin/create-wasm-app.js"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "webpack --config webpack.config.js",
|
|
||||||
"start": "webpack-dev-server"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/rustwasm/create-wasm-app.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"webassembly",
|
|
||||||
"wasm",
|
|
||||||
"rust",
|
|
||||||
"webpack"
|
|
||||||
],
|
|
||||||
"author": "Ashley Williams <ashley666ashley@gmail.com>",
|
|
||||||
"license": "(MIT OR Apache-2.0)",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/rustwasm/create-wasm-app/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/rustwasm/create-wasm-app#readme",
|
|
||||||
"devDependencies": {
|
|
||||||
"basegl": "file:../../target/web",
|
|
||||||
"hello-wasm-pack": "^0.1.0",
|
|
||||||
"webpack": "^4.29.3",
|
|
||||||
"webpack-cli": "^3.1.0",
|
|
||||||
"webpack-dev-server": "^3.1.5",
|
|
||||||
"copy-webpack-plugin": "^5.0.0",
|
|
||||||
"html-webpack-plugin": "^3.2.0"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: "./bootstrap.js",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist"),
|
|
||||||
filename: "bootstrap.js",
|
|
||||||
},
|
|
||||||
mode: "development",
|
|
||||||
plugins: [
|
|
||||||
new CopyWebpackPlugin(['index.html']),
|
|
||||||
// new HtmlWebpackPlugin({template: 'index.html'}),
|
|
||||||
],
|
|
||||||
};
|
|
@ -1,47 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "basegl"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Wojciech Danilo <wojciech.danilo@gmail.com>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
crate-type = ["cdylib"]
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
basegl-prelude = { version = "0.1.0" , path = "../prelude" }
|
|
||||||
structology = { version = "0.1.0" , path = "../structology/core" }
|
|
||||||
wasm-bindgen = { version = "^0.2" , features = ["nightly"] }
|
|
||||||
js-sys = { version = "0.3.28" }
|
|
||||||
failure = { version = "0.1.5" }
|
|
||||||
derive_more = { version = "0.15.0" }
|
|
||||||
shrinkwraprs = { version = "0.2.1" }
|
|
||||||
itertools = { version = "0.8" }
|
|
||||||
nalgebra = { version = "0.18.1" }
|
|
||||||
bit_field = { version = "0.10.0" }
|
|
||||||
paste = { version = "0.1.6" }
|
|
||||||
enum_dispatch = { version = "= 0.1.3" } # https://gitlab.com/antonok/enum_dispatch/issues/10
|
|
||||||
typenum = { version = "1.11.2" }
|
|
||||||
rustc-hash = { version = "1.0.1" }
|
|
||||||
console_error_panic_hook = { version = "0.1.6" }
|
|
||||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
|
||||||
serde_json = { version = "1.0" }
|
|
||||||
|
|
||||||
[dependencies.web-sys]
|
|
||||||
version = "0.3.4"
|
|
||||||
features = [
|
|
||||||
'Document',
|
|
||||||
'Element',
|
|
||||||
'HtmlCanvasElement',
|
|
||||||
'WebGlBuffer',
|
|
||||||
'WebGlRenderingContext',
|
|
||||||
'WebGlProgram',
|
|
||||||
'WebGlShader',
|
|
||||||
'Window',
|
|
||||||
'console'
|
|
||||||
]
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
wasm-bindgen-test = "0.2"
|
|
@ -1,136 +0,0 @@
|
|||||||
use crate::data::function::nop::NOP;
|
|
||||||
use crate::prelude::*;
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
// =====================
|
|
||||||
// === Callback Type ===
|
|
||||||
// =====================
|
|
||||||
|
|
||||||
pub type NoCallback = ();
|
|
||||||
|
|
||||||
#[derive(Shrinkwrap)]
|
|
||||||
#[shrinkwrap(mutable)]
|
|
||||||
pub struct Callback<Func>(pub Func);
|
|
||||||
|
|
||||||
impl<Func> Default for Callback<Func> {
|
|
||||||
fn default() -> Self {
|
|
||||||
// Callback(NOP::nop())
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Func> fmt::Debug for Callback<Func> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "Callback")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================
|
|
||||||
// === Callback Interface ===
|
|
||||||
// ==========================
|
|
||||||
|
|
||||||
pub trait Callback0: 'static {
|
|
||||||
fn call(&mut self);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Callback1<Arg1> {
|
|
||||||
fn call(&mut self, arg1: Arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Callback2<Arg1, Arg2> {
|
|
||||||
fn call(&mut self, arg1: Arg1, arg2: Arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Callback3<Arg1, Arg2, Arg3> {
|
|
||||||
fn call(&mut self, arg1: Arg1, arg2: Arg2, arg3: Arg3);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Callback4<Arg1, Arg2, Arg3, Arg4> {
|
|
||||||
fn call(&mut self, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Callback5<Arg1, Arg2, Arg3, Arg4, Arg5> {
|
|
||||||
fn call(&mut self, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// === Unit Implementations ===
|
|
||||||
|
|
||||||
impl Callback0 for () {
|
|
||||||
fn call(&mut self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Arg1> Callback1<Arg1> for () {
|
|
||||||
fn call(&mut self, _arg1: Arg1) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Arg1, Arg2> Callback2<Arg1, Arg2> for () {
|
|
||||||
fn call(&mut self, _arg1: Arg1, _arg2: Arg2) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Arg1, Arg2, Arg3> Callback3<Arg1, Arg2, Arg3> for () {
|
|
||||||
fn call(&mut self, _arg1: Arg1, _arg2: Arg2, _arg3: Arg3) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Arg1, Arg2, Arg3, Arg4> Callback4<Arg1, Arg2, Arg3, Arg4> for () {
|
|
||||||
fn call(&mut self, _arg1: Arg1, _arg2: Arg2, _arg3: Arg3, _arg4: Arg4) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Arg1, Arg2, Arg3, Arg4, Arg5> Callback5<Arg1, Arg2, Arg3, Arg4, Arg5> for () {
|
|
||||||
fn call(&mut self, _arg1: Arg1, _arg2: Arg2, _arg3: Arg3, _arg4: Arg4, _arg5: Arg5) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === FnMut Implementations ===
|
|
||||||
|
|
||||||
// FIXME: How to make it more generic?
|
|
||||||
impl<T: 'static, P: 'static> Callback0 for WithPhantomType<Rc<Fn() -> T>, P> {
|
|
||||||
fn call(&mut self) {
|
|
||||||
(self.t)();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: How to make it more generic?
|
|
||||||
impl<Arg1, T: 'static, P: 'static> Callback1<Arg1> for WithPhantomType<Rc<Fn(Arg1) -> T>, P> {
|
|
||||||
fn call(&mut self, arg1: Arg1) {
|
|
||||||
(self.t)(arg1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: FnMut() -> T + 'static, T> Callback0 for F {
|
|
||||||
fn call(&mut self) {
|
|
||||||
self();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Arg1, F: FnMut(Arg1) -> T, T> Callback1<Arg1> for F {
|
|
||||||
fn call(&mut self, arg1: Arg1) {
|
|
||||||
self(arg1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Arg1, Arg2, F: FnMut(Arg1, Arg2) -> T, T> Callback2<Arg1, Arg2> for F {
|
|
||||||
fn call(&mut self, arg1: Arg1, arg2: Arg2) {
|
|
||||||
self(arg1, arg2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Arg1, Arg2, Arg3, F: FnMut(Arg1, Arg2, Arg3) -> T, T> Callback3<Arg1, Arg2, Arg3> for F {
|
|
||||||
fn call(&mut self, arg1: Arg1, arg2: Arg2, arg3: Arg3) {
|
|
||||||
self(arg1, arg2, arg3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Arg1, Arg2, Arg3, Arg4, F: FnMut(Arg1, Arg2, Arg3, Arg4) -> T, T>
|
|
||||||
Callback4<Arg1, Arg2, Arg3, Arg4> for F
|
|
||||||
{
|
|
||||||
fn call(&mut self, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4) {
|
|
||||||
self(arg1, arg2, arg3, arg4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Arg1, Arg2, Arg3, Arg4, Arg5, F: FnMut(Arg1, Arg2, Arg3, Arg4, Arg5) -> T, T>
|
|
||||||
Callback5<Arg1, Arg2, Arg3, Arg4, Arg5> for F
|
|
||||||
{
|
|
||||||
fn call(&mut self, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5) {
|
|
||||||
self(arg1, arg2, arg3, arg4, arg5);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
// #[macro_export]
|
|
||||||
// macro_rules! closure {
|
|
||||||
// ($name:ident
|
|
||||||
// <$($param:ident : $param_type:ty),*>
|
|
||||||
// ($($arg:ident : $arg_type:ty),*)
|
|
||||||
// |$($larg:ident : $larg_type:ty),*|
|
|
||||||
// $body:tt
|
|
||||||
// ) => {
|
|
||||||
// closure!( $name<$($param:$param_type),*>
|
|
||||||
// ($($arg:$arg_type),*)
|
|
||||||
// ($($larg:$larg_type)*)
|
|
||||||
// $body
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
// ($name:ident
|
|
||||||
// <$($param:ident : $param_type:ty),*>
|
|
||||||
// ($($arg:ident : $arg_type:ty),*)
|
|
||||||
// || $body:tt) => {
|
|
||||||
// closure!($name<$($param:$param_type),*>($($arg:$arg_type),*)()$body);
|
|
||||||
// };
|
|
||||||
// ($name:ident
|
|
||||||
// <$($param:ident : $param_type:ty),*>
|
|
||||||
// ($($arg:ident : $arg_type:ty),*)
|
|
||||||
// ($($larg:ident : $larg_type:ty),*)
|
|
||||||
// $body:tt
|
|
||||||
// ) => { paste::item! {
|
|
||||||
// pub type [<Closure_ $name>]<$($param),*> =
|
|
||||||
// impl Fn($($larg_type),*) + Clone;
|
|
||||||
// pub fn $name<$($param:$param_type),*>
|
|
||||||
// ($($arg:$arg_type),*) -> [<Closure_ $name>]<$($param),*> {
|
|
||||||
// move |$($larg),*| $body
|
|
||||||
// }
|
|
||||||
// }};
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! closure {
|
|
||||||
($name:ident
|
|
||||||
<$($param:ident : $param_type:ty),*>
|
|
||||||
($($arg:ident : $arg_type:ty),*)
|
|
||||||
|$($larg:ident : $larg_type:ty),*|
|
|
||||||
$body:tt
|
|
||||||
) => {
|
|
||||||
closure!( $name<$($param:$param_type),*>
|
|
||||||
($($arg:$arg_type),*)
|
|
||||||
($($larg:$larg_type)*)
|
|
||||||
$body
|
|
||||||
);
|
|
||||||
};
|
|
||||||
($name:ident
|
|
||||||
<$($param:ident : $param_type:ty),*>
|
|
||||||
($($arg:ident : $arg_type:ty),*)
|
|
||||||
|| $body:tt) => {
|
|
||||||
closure!($name<$($param:$param_type),*>($($arg:$arg_type),*)()$body);
|
|
||||||
};
|
|
||||||
($name:ident
|
|
||||||
<$($param:ident : $param_type:ty),*>
|
|
||||||
($($arg:ident : $arg_type:ty),*)
|
|
||||||
($($larg:ident : $larg_type:ty),*)
|
|
||||||
$body:tt
|
|
||||||
) => { paste::item! {
|
|
||||||
#[cfg(not(feature = "no_unboxed_callbacks"))]
|
|
||||||
pub type [<Closure_ $name>]<$($param),*> =
|
|
||||||
impl Fn($($larg_type),*) + Clone;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_unboxed_callbacks"))]
|
|
||||||
pub fn $name<$($param:$param_type),*>
|
|
||||||
($($arg:$arg_type),*) -> [<Closure_ $name>]<$($param),*> {
|
|
||||||
move |$($larg),*| $body
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "no_unboxed_callbacks")]
|
|
||||||
pub type [<Closure_ $name>]<$($param),*> =
|
|
||||||
WithPhantomType<Rc<dyn Fn($($larg_type),*)>, $($param),*>;
|
|
||||||
|
|
||||||
#[cfg(feature = "no_unboxed_callbacks")]
|
|
||||||
pub fn $name<$($param:$param_type),*>
|
|
||||||
($($arg:$arg_type),*)
|
|
||||||
-> WithPhantomType<Rc<dyn Fn($($larg_type),*)>, $($param),*> {
|
|
||||||
WithPhantomType::new(Rc::new(move |$($larg),*| $body))
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
pub mod callback;
|
|
||||||
pub mod closure;
|
|
||||||
pub mod nop;
|
|
@ -1,39 +0,0 @@
|
|||||||
// ===========
|
|
||||||
// === NOP ===
|
|
||||||
// ===========
|
|
||||||
|
|
||||||
pub trait NOP {
|
|
||||||
fn nop() -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NOP for () {
|
|
||||||
fn nop() -> Self {
|
|
||||||
()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T1> NOP for fn(T1) {
|
|
||||||
fn nop() -> Self {
|
|
||||||
|_| {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T1, T2> NOP for fn(T1, T2) {
|
|
||||||
fn nop() -> Self {
|
|
||||||
|_, _| {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T1, T2, T3> NOP for fn(T1, T2, T3) {
|
|
||||||
fn nop() -> Self {
|
|
||||||
|_, _, _| {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T1, T2, T3, T4> NOP for fn(T1, T2, T3, T4) {
|
|
||||||
fn nop() -> Self {
|
|
||||||
|_, _, _, _| {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T1, T2, T3, T4, T5> NOP for fn(T1, T2, T3, T4, T5) {
|
|
||||||
fn nop() -> Self {
|
|
||||||
|_, _, _, _, _| {}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
pub mod function;
|
|
||||||
pub mod opt_vec;
|
|
||||||
pub mod shared;
|
|
@ -1,104 +0,0 @@
|
|||||||
use crate::prelude::*;
|
|
||||||
use std::iter::FilterMap;
|
|
||||||
use std::slice;
|
|
||||||
|
|
||||||
// ==============
|
|
||||||
// === OptVec ===
|
|
||||||
// ==============
|
|
||||||
|
|
||||||
/// A contiguous growable sparse array type. Similar to `Vec<T>`, but allowing
|
|
||||||
/// missing values. After a value is removed, it remembers the index for reuse
|
|
||||||
/// in the future.
|
|
||||||
#[derive(Derivative)]
|
|
||||||
#[derivative(Default(bound = ""))]
|
|
||||||
#[derive(Clone, Debug, Shrinkwrap)]
|
|
||||||
pub struct OptVec<T> {
|
|
||||||
#[shrinkwrap(main_field)]
|
|
||||||
pub vec : Vec<Option<T>>,
|
|
||||||
pub free : Vec<Ix>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Ix = usize;
|
|
||||||
pub type Iter<'t, T> = FilterMap<slice::Iter<'t, Option<T>>, OptionAsRef<T>>;
|
|
||||||
pub type IterMut<'t, T> = FilterMap<slice::IterMut<'t, Option<T>>, OptionAsRefMut<T>>;
|
|
||||||
pub type OptionAsRef<T> = for<'r> fn(&'r Option<T>) -> Option<&'r T>;
|
|
||||||
pub type OptionAsRefMut<T> = for<'r> fn(&'r mut Option<T>) -> Option<&'r mut T>;
|
|
||||||
|
|
||||||
impl<T> OptVec<T> {
|
|
||||||
/// Constructs a new, empty `Vec<T>`. It will not allocate until elements
|
|
||||||
/// are pushed onto it.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let vec = default();
|
|
||||||
let free = default();
|
|
||||||
Self { vec, free }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(&mut self, item: T) -> Ix {
|
|
||||||
self.insert_with_ix(|_| item)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter(&self) -> Iter<T> {
|
|
||||||
self.vec.iter().filter_map(Option::as_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter_mut(&mut self) -> IterMut<T> {
|
|
||||||
self.vec.iter_mut().filter_map(Option::as_mut)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds a free index and inserts the element. The index is re-used in case
|
|
||||||
/// the array is sparse or is added in case of no free places.
|
|
||||||
pub fn insert_with_ix<F: FnOnce(Ix) -> T>(&mut self, f: F) -> Ix {
|
|
||||||
match self.free.pop() {
|
|
||||||
None => {
|
|
||||||
let ix = self.vec.len();
|
|
||||||
self.vec.push(Some(f(ix)));
|
|
||||||
ix
|
|
||||||
}
|
|
||||||
Some(ix) => {
|
|
||||||
self.vec[ix] = Some(f(ix));
|
|
||||||
ix
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes the element at provided index and marks the index to be reused.
|
|
||||||
/// Does nothing if the index was already empty. Panics if the index was out
|
|
||||||
/// of bounds.
|
|
||||||
pub fn remove(&mut self, ix: Ix) -> Option<T> {
|
|
||||||
let item = self.vec[ix].take();
|
|
||||||
item.iter().for_each(|_| self.free.push(ix));
|
|
||||||
item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Index<usize> for OptVec<T> {
|
|
||||||
type Output = T;
|
|
||||||
fn index(&self, ix: usize) -> &Self::Output {
|
|
||||||
self.vec.index(ix).as_ref().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> IndexMut<usize> for OptVec<T> {
|
|
||||||
fn index_mut(&mut self, ix: usize) -> &mut Self::Output {
|
|
||||||
self.vec.index_mut(ix).as_mut().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_add() {
|
|
||||||
let mut v = OptVec::new();
|
|
||||||
let ix1 = v.insert(1);
|
|
||||||
let ix2 = v.insert(2);
|
|
||||||
v.remove(ix1);
|
|
||||||
let ix3 = v.insert(3);
|
|
||||||
let ix4 = v.insert(4);
|
|
||||||
assert_eq!(ix1, 0);
|
|
||||||
assert_eq!(ix2, 1);
|
|
||||||
assert_eq!(ix3, 0);
|
|
||||||
assert_eq!(ix4, 2);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
use std::cell::Ref;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::cell::RefMut;
|
|
||||||
use std::fmt;
|
|
||||||
use std::ops::Deref;
|
|
||||||
use std::ops::DerefMut;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::rc::Weak;
|
|
||||||
|
|
||||||
// ==============
|
|
||||||
// === Shared ===
|
|
||||||
// ==============
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Shared<T> {
|
|
||||||
v: Rc<RefCell<T>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <T> Shared<T> {
|
|
||||||
pub fn new(t: T)-> Shared<T> {
|
|
||||||
Shared{v: Rc::new(RefCell::new(t))}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <T> Shared<T> {
|
|
||||||
pub fn clone_ref(&self) -> Self {
|
|
||||||
Self { v: self.v.clone() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn borrow(&self) -> Ref<T> {
|
|
||||||
self.v.borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn borrow_mut(&self) -> RefMut<T> {
|
|
||||||
self.v.borrow_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ptr(&self) -> *mut T {
|
|
||||||
self.v.as_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn downgrade(&self) -> WeakShared<T> {
|
|
||||||
WeakShared { raw: Rc::downgrade(&self.v) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl <T: fmt::Display> fmt::Display for Shared<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.deref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <T: fmt::Debug> fmt::Debug for Shared<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{:?}", self.deref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <T> Deref for Shared<T>{
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn deref(&self) -> &T {
|
|
||||||
unsafe {self.as_ptr().as_ref().unwrap()}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <T> DerefMut for Shared<T> {
|
|
||||||
#[inline]
|
|
||||||
fn deref_mut(&mut self) -> &mut T {
|
|
||||||
unsafe {self.as_ptr().as_mut().unwrap()}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==================
|
|
||||||
// === WeakShared ===
|
|
||||||
// ==================
|
|
||||||
|
|
||||||
pub struct WeakShared<T> {
|
|
||||||
raw: Weak<RefCell<T>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> WeakShared<T> {
|
|
||||||
pub fn upgrade(&self) -> Option<Shared<T>> {
|
|
||||||
let opt_raw = self.raw.upgrade();
|
|
||||||
opt_raw.map(|v| Shared { v })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <T: fmt::Debug> fmt::Debug for WeakShared<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{:?}", self.deref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn split (s: Shared<String>) -> Vec<String> {
|
|
||||||
// s.split_whitespace().map(|s| s.to_string()).collect()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn main() {
|
|
||||||
// let s = Shared::new("hello".to_string());
|
|
||||||
// let s2 = s.clone();
|
|
||||||
// s2.borrow_mut().push('!');
|
|
||||||
// println!("{:?}",s2);
|
|
||||||
|
|
||||||
// // Deref kicking in...
|
|
||||||
// let n = s2.len();
|
|
||||||
|
|
||||||
// println!("{:?}", n);
|
|
||||||
|
|
||||||
// // mutation has to be explicit
|
|
||||||
// s2.borrow_mut().push_str(" dolly");
|
|
||||||
|
|
||||||
// println!("{:?} {}",s2.borrow(), s);
|
|
||||||
|
|
||||||
// println!("{:?}", split(s2.clone()));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
@ -1,608 +0,0 @@
|
|||||||
#![feature(type_ascription)]
|
|
||||||
#![feature(unboxed_closures)]
|
|
||||||
#![cfg_attr(test, allow(dead_code))]
|
|
||||||
#![feature(trait_alias)]
|
|
||||||
#![feature(type_alias_impl_trait)]
|
|
||||||
#![feature(proc_macro_hygiene)]
|
|
||||||
#![feature(specialization)]
|
|
||||||
#![feature(weak_into_raw)]
|
|
||||||
#![feature(associated_type_defaults)]
|
|
||||||
#![feature(set_stdio)]
|
|
||||||
#![feature(overlapping_marker_traits)]
|
|
||||||
//#![warn(missing_docs)]
|
|
||||||
|
|
||||||
// Lints. To be refactored after this gets resolved: https://github.com/rust-lang/cargo/issues/5034
|
|
||||||
#![allow(clippy::option_map_unit_fn)]
|
|
||||||
|
|
||||||
#![feature(generators, generator_trait)]
|
|
||||||
|
|
||||||
|
|
||||||
use std::ops::{Generator, GeneratorState};
|
|
||||||
use std::pin::Pin;
|
|
||||||
|
|
||||||
pub use basegl_prelude as prelude;
|
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
use prelude::*;
|
|
||||||
use structology::*;
|
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use serde_json;
|
|
||||||
|
|
||||||
#[derive(Iterator)]
|
|
||||||
pub struct Demo<T> (T, u32, T);
|
|
||||||
// pub struct Demo<T> { t: T, x:u32, z:T }
|
|
||||||
|
|
||||||
// struct Demo<'a, T: ?Sized> {
|
|
||||||
// a: Box<T>,
|
|
||||||
// b: u8,
|
|
||||||
// c: &'a str,
|
|
||||||
// d: String,
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub type Stream<T> = Vec<T>;
|
|
||||||
|
|
||||||
|
|
||||||
// ============
|
|
||||||
// === Tree ===
|
|
||||||
// ============
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct Tree<K,V> where K: Eq + Hash {
|
|
||||||
pub value : Option<V>,
|
|
||||||
pub branches : HashMap<K, Tree<K,V>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===============
|
|
||||||
// === Shifted ===
|
|
||||||
// ===============
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Shrinkwrap)]
|
|
||||||
#[shrinkwrap(mutable)]
|
|
||||||
pub struct Shifted<T> {
|
|
||||||
#[shrinkwrap(main_field)]
|
|
||||||
pub wrapped : T,
|
|
||||||
pub off : usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct ShiftedVec1<T> {
|
|
||||||
pub head: T,
|
|
||||||
pub tail: Vec<Shifted<T>>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ===============
|
|
||||||
// === Layered ===
|
|
||||||
// ===============
|
|
||||||
|
|
||||||
pub trait Layer<T> {
|
|
||||||
fn layered(t: T) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[derive(Shrinkwrap)]
|
|
||||||
#[shrinkwrap(mutable)]
|
|
||||||
pub struct Layered<T>(pub T);
|
|
||||||
|
|
||||||
impl<T> Layer<T> for Layered<T> {
|
|
||||||
fn layered(t: T) -> Self { Layered(t) }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ===========
|
|
||||||
// === AST ===
|
|
||||||
// ===========
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Shrinkwrap, Serialize, Deserialize)]
|
|
||||||
#[shrinkwrap(mutable)]
|
|
||||||
pub struct Ast {
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub wrapped: Rc<WithID<WithSpan<Shape<Ast>>>>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Ast {
|
|
||||||
fn iter(&self) -> Rc<dyn Iterator<Item = &'_ Shape<Ast>> + '_> {
|
|
||||||
Rc::new(IterGen(move || {
|
|
||||||
let curr = &self.wrapped.wrapped.wrapped;
|
|
||||||
yield curr;
|
|
||||||
|
|
||||||
if let Shape::App(t) = curr {
|
|
||||||
for elem in (*t.func).iter() { yield elem }
|
|
||||||
for elem in (*t.arg).iter() { yield elem }
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Spanned + Into<Shape<Ast>>>
|
|
||||||
From<T> for Ast {
|
|
||||||
fn from(t: T) -> Self {
|
|
||||||
let span = t.span();
|
|
||||||
let shape = t.into();
|
|
||||||
let with_span = WithSpan { wrapped: shape, span };
|
|
||||||
let with_id = WithID { wrapped: with_span, id: None };
|
|
||||||
Ast { wrapped: Rc::new(with_id) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============
|
|
||||||
// === Shape ===
|
|
||||||
// =============
|
|
||||||
|
|
||||||
#[ast(flat)] pub enum Shape<T> {
|
|
||||||
|
|
||||||
// === Identifiers ===
|
|
||||||
Blank { },
|
|
||||||
Var { name : String },
|
|
||||||
Cons { name : String },
|
|
||||||
Opr { name : String },
|
|
||||||
Mod { name : String },
|
|
||||||
|
|
||||||
// === Literals ===
|
|
||||||
Number { base: Option<String>, int: String },
|
|
||||||
Text (Text<T>),
|
|
||||||
|
|
||||||
// === Expressions ===
|
|
||||||
App { func : T , off : usize , arg: T },
|
|
||||||
Infix { larg : T , loff : usize , opr: Opr , roff: usize , rarg: T },
|
|
||||||
SectLeft { arg : T , off : usize , opr: Opr },
|
|
||||||
SectRight { opr : Opr , off : usize , arg: T },
|
|
||||||
SectSides { opr : Opr },
|
|
||||||
|
|
||||||
Invalid (Invalid<T>),
|
|
||||||
Block (Block<T>),
|
|
||||||
Module (Module<T>),
|
|
||||||
Macro (Macro<T>),
|
|
||||||
Comment (Comment),
|
|
||||||
Import (Import<T>),
|
|
||||||
Mixfix (Mixfix<T>),
|
|
||||||
Group (Group<T>),
|
|
||||||
Def (Def<T>),
|
|
||||||
Foreign (Foreign),
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===============
|
|
||||||
// === Invalid ===
|
|
||||||
// ===============
|
|
||||||
|
|
||||||
#[ast] pub enum Invalid<T> {
|
|
||||||
Unrecognized { input : String },
|
|
||||||
Unexpected { msg : String, stream: Stream<T> },
|
|
||||||
InvalidSuffex { elem : T, suffix: String },
|
|
||||||
// DanglingBase
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ============
|
|
||||||
// === Text ===
|
|
||||||
// ============
|
|
||||||
|
|
||||||
#[ast] pub enum Text<T> {
|
|
||||||
Raw { body: TextBody<TextRawSegment> },
|
|
||||||
Fmt { body: TextBody<TextFmtSegment<T>> }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub struct TextRawSegment {
|
|
||||||
pub value: String
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub enum TextFmtSegment<T> {
|
|
||||||
Plain { value : String },
|
|
||||||
Expr { value : Option<T> },
|
|
||||||
Escape { escape : TextEscape },
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type TextBlock<T> = Vec<TextLine<T>>;
|
|
||||||
#[ast] pub struct TextLine<T> { off: usize, elems: Vec<T> }
|
|
||||||
#[ast] pub struct TextBody<T> { quote: TextQuote, block: TextBlock<T> }
|
|
||||||
#[ast] pub enum TextQuote { Single, Triple }
|
|
||||||
#[ast] pub struct TextEscape {} // TODO
|
|
||||||
|
|
||||||
|
|
||||||
// =============
|
|
||||||
// === Block ===
|
|
||||||
// =============
|
|
||||||
|
|
||||||
#[ast] pub struct Block<T> {
|
|
||||||
ty : BlockType,
|
|
||||||
ident : usize,
|
|
||||||
empty_lines : usize,
|
|
||||||
first_line : BlockLine<T>,
|
|
||||||
lines : Vec<BlockLine<Option<T>>>,
|
|
||||||
is_orphan : bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub enum BlockType { Continuous, Discontinuous }
|
|
||||||
#[ast] pub struct BlockLine <T> { elem: T, off: usize }
|
|
||||||
|
|
||||||
// ==============
|
|
||||||
// === Module ===
|
|
||||||
// ==============
|
|
||||||
|
|
||||||
#[ast] pub struct Module<T> { lines: Vec<BlockLine<Option<T>>> }
|
|
||||||
|
|
||||||
// =============
|
|
||||||
// === Macro ===
|
|
||||||
// =============
|
|
||||||
|
|
||||||
#[ast] pub enum Macro<T> {
|
|
||||||
Match (Match<T>),
|
|
||||||
Ambiguous (Ambiguous),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub struct MacroMatch<T> {
|
|
||||||
pub pfx : Option<MacroPatternMatch<Ast>>,
|
|
||||||
pub segs : ShiftedVec1<MacroMatchSegment<T>>,
|
|
||||||
pub resolved : Ast
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub struct MacroAmbiguous {
|
|
||||||
pub segs : ShiftedVec1<MacroAmbiguousSegment>,
|
|
||||||
// pub paths : Tree<Ast, ()>, // FIXME
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub struct MacroMatchSegment<T> {
|
|
||||||
pub head : Ast,
|
|
||||||
pub body : MacroPatternMatch<Shifted<T>>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub struct MacroAmbiguousSegment {
|
|
||||||
pub head: Ast,
|
|
||||||
pub body: Option<Shifted<Ast>>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type MacroPattern = Rc<MacroPatternRaw>;
|
|
||||||
#[ast] pub enum MacroPatternRaw {
|
|
||||||
|
|
||||||
// === Boundary Patterns ===
|
|
||||||
Begin ,
|
|
||||||
End ,
|
|
||||||
|
|
||||||
// === Structural Patterns ===
|
|
||||||
Nothing ,
|
|
||||||
Seq { pat1 : MacroPattern , pat2 : MacroPattern },
|
|
||||||
Or { pat1 : MacroPattern , pat2 : MacroPattern },
|
|
||||||
Many { pat : MacroPattern },
|
|
||||||
Except { not : MacroPattern, pat : MacroPattern },
|
|
||||||
|
|
||||||
// === Meta Patterns ===
|
|
||||||
Build { pat : MacroPattern },
|
|
||||||
Err { msg : String , pat : MacroPattern },
|
|
||||||
Tag { tag : String , pat : MacroPattern },
|
|
||||||
Cls { cls : PatternClass , pat : MacroPattern },
|
|
||||||
|
|
||||||
// === Token Patterns ===
|
|
||||||
Tok { spaced : Spaced , ast : Ast },
|
|
||||||
Blank { spaced : Spaced },
|
|
||||||
Var { spaced : Spaced },
|
|
||||||
Cons { spaced : Spaced },
|
|
||||||
Opr { spaced : Spaced , max_prec : Option<usize> },
|
|
||||||
Mod { spaced : Spaced },
|
|
||||||
Num { spaced : Spaced },
|
|
||||||
Text { spaced : Spaced },
|
|
||||||
Block { spaced : Spaced },
|
|
||||||
Macro { spaced : Spaced },
|
|
||||||
Invalid { spaced : Spaced },
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub enum PatternClass { Normal, Pattern }
|
|
||||||
pub type Spaced = Option<bool>;
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum Either<L,R> { Left(L), Right(R) }
|
|
||||||
pub type Switch<T> = Either<T,T>;
|
|
||||||
|
|
||||||
pub type MacroPatternMatch<T> = Rc<FooRaw<T>>;
|
|
||||||
#[ast] pub enum FooRaw<T> {
|
|
||||||
|
|
||||||
// === Boundary Matches ===
|
|
||||||
Begin { pat: MacroPatternRawBegin },
|
|
||||||
End { pat: MacroPatternRawEnd },
|
|
||||||
|
|
||||||
// === Structural Matches ===
|
|
||||||
Nothing { pat: MacroPatternRawNothing },
|
|
||||||
Seq { pat: MacroPatternRawSeq , elem: (MacroPatternMatch<T>, MacroPatternMatch<T>) },
|
|
||||||
Or { pat: MacroPatternRawOr , elem: Switch<MacroPatternMatch<T>>},
|
|
||||||
Many { pat: MacroPatternRawMany , elem: Vec<MacroPatternMatch<T>> },
|
|
||||||
Except { pat: MacroPatternRawExcept , elem: MacroPatternMatch<T> },
|
|
||||||
|
|
||||||
// === Meta Matches ===
|
|
||||||
Build { pat: MacroPatternRawBuild , elem: T },
|
|
||||||
Err { pat: MacroPatternRawErr , elem: T },
|
|
||||||
Tag { pat: MacroPatternRawTag , elem: MacroPatternMatch<T> },
|
|
||||||
Cls { pat: MacroPatternRawCls , elem: MacroPatternMatch<T> },
|
|
||||||
|
|
||||||
// === Token Matches ===
|
|
||||||
Tok { pat: MacroPatternRawTok , elem: T },
|
|
||||||
Blank { pat: MacroPatternRawBlank , elem: T },
|
|
||||||
Var { pat: MacroPatternRawVar , elem: T },
|
|
||||||
Cons { pat: MacroPatternRawCons , elem: T },
|
|
||||||
Opr { pat: MacroPatternRawOpr , elem: T },
|
|
||||||
Mod { pat: MacroPatternRawMod , elem: T },
|
|
||||||
Num { pat: MacroPatternRawNum , elem: T },
|
|
||||||
Text { pat: MacroPatternRawText , elem: T },
|
|
||||||
Block { pat: MacroPatternRawBlock , elem: T },
|
|
||||||
Macro { pat: MacroPatternRawMacro , elem: T },
|
|
||||||
Invalid { pat: MacroPatternRawInvalid , elem: T },
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// === Spaceless AST ===========================================================
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
#[ast] pub struct Comment {
|
|
||||||
pub lines: Vec<String>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub struct Import<T> {
|
|
||||||
pub lines: Vec<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub struct Mixfix<T> {
|
|
||||||
pub name: Vec<T>,
|
|
||||||
pub args: Vec<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub struct Group<T> {
|
|
||||||
pub body: Option<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub struct Def<T> {
|
|
||||||
pub name: Cons,
|
|
||||||
pub args: Vec<T>,
|
|
||||||
pub body: Option<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ast] pub struct Foreign {
|
|
||||||
pub indent : usize,
|
|
||||||
pub lang : String,
|
|
||||||
pub code : Vec<String>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// === Spaceless AST ===========================================================
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl Var {
|
|
||||||
pub fn new(name: String) -> Ast {
|
|
||||||
Ast::from (Var { name })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Spanned for Var {}
|
|
||||||
|
|
||||||
impl<T> Shape<T> {
|
|
||||||
pub fn iter(&self) -> Box<dyn Iterator<Item = &'_ T> + '_> {
|
|
||||||
Box::new(IterGen(move || {
|
|
||||||
match self {
|
|
||||||
Shape::App(t) => { yield &t.func; yield &t.arg; }
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Visitor<'t> {
|
|
||||||
pub to_be_visited: Vec<&'t mut Ast>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'t> Visitor<'t> {
|
|
||||||
pub fn visit(&mut self, t: &'t mut Ast) {
|
|
||||||
self.to_be_visited.push(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InstancedVisitor<'t, Instance> {
|
|
||||||
pub visitor : Visitor<'t>,
|
|
||||||
pub instance : Instance
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'t, Instance> InstancedVisitor<'t, Instance>
|
|
||||||
where Instance: VisitorFor<'t, App<Ast>> {
|
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
|
||||||
// loop {
|
|
||||||
// match self.visitor.to_be_visited.pop() {
|
|
||||||
// None => break,
|
|
||||||
// Some(t) => self.step(t)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn step(&mut self, t: &'t mut Shape<Ast>) {
|
|
||||||
match t {
|
|
||||||
Shape::App(t) => self.instance.visit(&mut self.visitor, t),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub trait VisitorFor<'t, T: 't>
|
|
||||||
where &'t mut T: IntoIterator<Item = &'t mut Ast> {
|
|
||||||
fn visit(&mut self, visitor: &mut Visitor<'t>, t: &'t mut T) {
|
|
||||||
t.into_iter().for_each(|s| visitor.visit(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===========
|
|
||||||
// === AST ===
|
|
||||||
// ===========
|
|
||||||
|
|
||||||
pub trait Spanned {
|
|
||||||
fn span(&self) -> usize { 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// === WithID ===
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Shrinkwrap, Serialize, Deserialize)]
|
|
||||||
#[shrinkwrap(mutable)]
|
|
||||||
pub struct WithID<T> {
|
|
||||||
#[shrinkwrap(main_field)]
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub wrapped: T,
|
|
||||||
pub id: Option<i32>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, S:Layer<T>>
|
|
||||||
Layer<T> for WithID<S> {
|
|
||||||
fn layered(t: T) -> Self {
|
|
||||||
WithID { wrapped: Layer::layered(t), id: None }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === WithSpan ===
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Shrinkwrap, Serialize, Deserialize)]
|
|
||||||
#[shrinkwrap(mutable)]
|
|
||||||
pub struct WithSpan<T> {
|
|
||||||
#[shrinkwrap(main_field)]
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub wrapped: T,
|
|
||||||
pub span: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Spanned for WithSpan<T> {
|
|
||||||
fn span(&self) -> usize { self.span }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T:Spanned, S:Layer<T>>
|
|
||||||
Layer<T> for WithSpan<S> {
|
|
||||||
fn layered(t: T) -> Self {
|
|
||||||
let span = t.span();
|
|
||||||
WithSpan { wrapped: Layer::layered(t), span }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl<T> Spanned for Shape<T>{}
|
|
||||||
|
|
||||||
// ==== boilerplate
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub struct IterGen<G: Generator>(pub G);
|
|
||||||
|
|
||||||
impl<G> Iterator for IterGen<G>
|
|
||||||
where G: Generator<Return = ()> + Unpin {
|
|
||||||
type Item = G::Yield;
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
match { Pin::new(&mut self.0).resume() } {
|
|
||||||
GeneratorState::Yielded(element) => Some(element),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =============
|
|
||||||
// === Utils ===
|
|
||||||
// =============
|
|
||||||
|
|
||||||
use console_error_panic_hook;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let a = Var { name: "foo".to_string() };
|
|
||||||
let b: Shape<Ast> = Shape::from(a);
|
|
||||||
let c: Ast = Ast::from(b);
|
|
||||||
let serialized = serde_json::to_string(&c).unwrap();
|
|
||||||
let d: Ast = serde_json::from_str(&serialized).unwrap();
|
|
||||||
println!("serialized = {}", serialized);
|
|
||||||
println!("deserialized = {:?}", d);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen(start)]
|
|
||||||
pub fn start() {
|
|
||||||
console_error_panic_hook::set_once();
|
|
||||||
set_stdout();
|
|
||||||
main();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////
|
|
||||||
|
|
||||||
type PrintFn = fn(&str) -> std::io::Result<()>;
|
|
||||||
|
|
||||||
struct Printer {
|
|
||||||
printfn: PrintFn,
|
|
||||||
buffer: String,
|
|
||||||
is_buffered: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Printer {
|
|
||||||
fn new(printfn: PrintFn, is_buffered: bool) -> Printer {
|
|
||||||
Printer {
|
|
||||||
buffer: String::new(),
|
|
||||||
printfn,
|
|
||||||
is_buffered,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::io::Write for Printer {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
|
||||||
self.buffer.push_str(&String::from_utf8_lossy(buf));
|
|
||||||
|
|
||||||
if !self.is_buffered {
|
|
||||||
(self.printfn)(&self.buffer)?;
|
|
||||||
self.buffer.clear();
|
|
||||||
|
|
||||||
return Ok(buf.len());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(i) = self.buffer.rfind('\n') {
|
|
||||||
let buffered = {
|
|
||||||
let (first, last) = self.buffer.split_at(i);
|
|
||||||
(self.printfn)(first)?;
|
|
||||||
|
|
||||||
String::from(&last[1..])
|
|
||||||
};
|
|
||||||
|
|
||||||
self.buffer.clear();
|
|
||||||
self.buffer.push_str(&buffered);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) -> std::io::Result<()> {
|
|
||||||
(self.printfn)(&self.buffer)?;
|
|
||||||
self.buffer.clear();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _print(msg: &str) -> std::io::Result<()> {
|
|
||||||
web_sys::console::info_1(&msg.to_string().into());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn set_stdout() {
|
|
||||||
let printer = Printer::new(_print, true);
|
|
||||||
std::io::set_print(Some(Box::new(printer)));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_stdout_unbuffered() {
|
|
||||||
let printer = Printer::new(_print, false);
|
|
||||||
std::io::set_print(Some(Box::new(printer)));
|
|
||||||
}
|
|
@ -1,358 +0,0 @@
|
|||||||
#![feature(type_ascription)]
|
|
||||||
#![feature(unboxed_closures)]
|
|
||||||
#![cfg_attr(test, allow(dead_code))]
|
|
||||||
#![feature(trait_alias)]
|
|
||||||
#![feature(type_alias_impl_trait)]
|
|
||||||
#![feature(proc_macro_hygiene)]
|
|
||||||
#![feature(specialization)]
|
|
||||||
#![feature(weak_into_raw)]
|
|
||||||
#![feature(associated_type_defaults)]
|
|
||||||
#![feature(set_stdio)]
|
|
||||||
#![feature(overlapping_marker_traits)]
|
|
||||||
//#![warn(missing_docs)]
|
|
||||||
|
|
||||||
// Lints. To be refactored after this gets resolved: https://github.com/rust-lang/cargo/issues/5034
|
|
||||||
#![allow(clippy::option_map_unit_fn)]
|
|
||||||
|
|
||||||
#![feature(generators, generator_trait)]
|
|
||||||
|
|
||||||
|
|
||||||
use std::ops::{Generator, GeneratorState};
|
|
||||||
use std::pin::Pin;
|
|
||||||
|
|
||||||
pub use basegl_prelude as prelude;
|
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
use prelude::*;
|
|
||||||
|
|
||||||
// =============
|
|
||||||
// === Shape ===
|
|
||||||
// =============
|
|
||||||
|
|
||||||
#[derive(Debug)] pub struct Var { name: String }
|
|
||||||
#[derive(Debug)] pub struct Opr { name: String }
|
|
||||||
#[derive(Debug)] pub struct App <T> { func: T, off: i32, arg: T }
|
|
||||||
#[derive(Debug)] pub struct SectLeft <T> { arg: T, off: i32, opr: Opr }
|
|
||||||
#[derive(Debug)] pub struct SectRight <T> { opr: Opr, off: i32, arg: T }
|
|
||||||
#[derive(Debug)] pub struct SectSides { opr: Opr }
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Shape<T> {
|
|
||||||
Var(Var),
|
|
||||||
App(App<T>),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type AppIterator<'t, T> = impl Iterator<Item = &'t T>;
|
|
||||||
pub fn app_iterator<'t, T>(t: &'t App<T>) -> AppIterator<'t, T> {
|
|
||||||
IterGen(move || {
|
|
||||||
yield &t.func;
|
|
||||||
yield &t.arg;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type AppIteratorMut<'t, T> = impl Iterator<Item = &'t mut T>;
|
|
||||||
pub fn app_iterator_mut<'t, T>(t: &'t mut App<T>) -> AppIteratorMut<'t, T> {
|
|
||||||
IterGen(move || {
|
|
||||||
yield &mut t.func;
|
|
||||||
yield &mut t.arg;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> App<T> {
|
|
||||||
pub fn iter(&self) -> Box<dyn Iterator<Item = &'_ T> + '_> {
|
|
||||||
Box::new(IterGen(move || {
|
|
||||||
yield &self.func;
|
|
||||||
yield &self.arg;
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'t, T> IntoIterator for &'t App<T> {
|
|
||||||
type Item = &'t T;
|
|
||||||
type IntoIter = AppIterator<'t, T>;
|
|
||||||
fn into_iter(self) -> AppIterator<'t, T> { app_iterator(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'t, T> IntoIterator for &'t mut App<T> {
|
|
||||||
type Item = &'t mut T;
|
|
||||||
type IntoIter = AppIteratorMut<'t, T>;
|
|
||||||
fn into_iter(self) -> AppIteratorMut<'t, T> { app_iterator_mut(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl<T> Shape<T> {
|
|
||||||
pub fn iter(&self) -> Box<dyn Iterator<Item = &'_ T> + '_> {
|
|
||||||
Box::new(IterGen(move || {
|
|
||||||
match self {
|
|
||||||
Shape::App(t) => { yield &t.func; yield &t.arg; }
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Visitor<'t> {
|
|
||||||
pub to_be_visited: Vec<&'t mut Ast>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'t> Visitor<'t> {
|
|
||||||
pub fn visit(&mut self, t: &'t mut Ast) {
|
|
||||||
self.to_be_visited.push(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InstancedVisitor<'t, Instance> {
|
|
||||||
pub visitor : Visitor<'t>,
|
|
||||||
pub instance : Instance
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'t, Instance> InstancedVisitor<'t, Instance>
|
|
||||||
where Instance: VisitorFor<'t, App<Ast>> {
|
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
|
||||||
loop {
|
|
||||||
match self.visitor.to_be_visited.pop() {
|
|
||||||
None => break,
|
|
||||||
Some(t) => self.step(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn step(&mut self, t: &'t mut Shape<Ast>) {
|
|
||||||
match t {
|
|
||||||
Shape::App(t) => self.instance.visit(&mut self.visitor, t),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub trait VisitorFor<'t, T: 't>
|
|
||||||
where &'t mut T: IntoIterator<Item = &'t mut Ast> {
|
|
||||||
fn visit(&mut self, visitor: &mut Visitor<'t>, t: &'t mut T) {
|
|
||||||
t.into_iter().for_each(|s| visitor.visit(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===========
|
|
||||||
// === AST ===
|
|
||||||
// ===========
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[derive(Shrinkwrap)]
|
|
||||||
#[shrinkwrap(mutable)]
|
|
||||||
pub struct WithID<T> {
|
|
||||||
#[shrinkwrap(main_field)]
|
|
||||||
pub wrapped: T,
|
|
||||||
pub id: Option<i32>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[derive(Shrinkwrap)]
|
|
||||||
#[shrinkwrap(mutable)]
|
|
||||||
pub struct WithSpan<T> {
|
|
||||||
#[shrinkwrap(main_field)]
|
|
||||||
pub wrapped: T,
|
|
||||||
pub span: i32
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[derive(Shrinkwrap)]
|
|
||||||
#[shrinkwrap(mutable)]
|
|
||||||
pub struct Ast {
|
|
||||||
pub wrapped: Box<WithID<WithSpan<Shape<Ast>>>>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Ast {
|
|
||||||
fn iter(&self) -> Box<dyn Iterator<Item = &'_ Shape<Ast>> + '_> {
|
|
||||||
Box::new(IterGen(move || {
|
|
||||||
let curr = &self.wrapped.wrapped.wrapped;
|
|
||||||
yield curr;
|
|
||||||
|
|
||||||
if let Shape::App(t) = curr {
|
|
||||||
for elem in t.func.iter() { yield elem }
|
|
||||||
for elem in t.arg.iter() { yield elem }
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ==== boilerplate
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub struct IterGen<G: Generator>(pub G);
|
|
||||||
|
|
||||||
impl<G> Iterator for IterGen<G>
|
|
||||||
where G: Generator<Return = ()> + Unpin {
|
|
||||||
type Item = G::Yield;
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
match { Pin::new(&mut self.0).resume() } {
|
|
||||||
GeneratorState::Yielded(element) => Some(element),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =============
|
|
||||||
// === Utils ===
|
|
||||||
// =============
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let node = |ast_of| Ast { wrapped: Box::new(WithID { wrapped: ast_of, id: None })};
|
|
||||||
|
|
||||||
// let ast = node(
|
|
||||||
// Shape::App {
|
|
||||||
// func: node(
|
|
||||||
// Shape::App {
|
|
||||||
// func: node(Shape::Var { name: "foo".to_owned() }),
|
|
||||||
// off: 0,
|
|
||||||
// arg: node(Shape::Var { name: "bar".to_owned() })
|
|
||||||
// }
|
|
||||||
// ),
|
|
||||||
// off: 0,
|
|
||||||
// arg: node(Shape::Var { name: "baz".to_owned() })
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
// let ast = mk_nodes(100000);
|
|
||||||
|
|
||||||
// let mut i: i32 = 0;
|
|
||||||
// for node in ast.iter() {
|
|
||||||
// // dbg!(node);
|
|
||||||
// i += 1;
|
|
||||||
// }
|
|
||||||
// dbg!(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn mk_nodes(depth: i32) -> Ast {
|
|
||||||
// let node = |ast_of| Ast { wrapped: Box::new(WithID { elem: ast_of, id: None })};
|
|
||||||
|
|
||||||
// let mut ast = node(Shape::App {
|
|
||||||
// func: node(Shape::Var { name: "foo".to_owned() }),
|
|
||||||
// off: 0,
|
|
||||||
// arg: node(Shape::Var { name: "bar".to_owned() })
|
|
||||||
// });
|
|
||||||
|
|
||||||
// for x in 0..depth {
|
|
||||||
// ast = node( Shape::App {
|
|
||||||
// func: node(Shape::Var { name: "foo".to_owned() }),
|
|
||||||
// off: 0,
|
|
||||||
// arg: ast
|
|
||||||
// })
|
|
||||||
// };
|
|
||||||
|
|
||||||
// ast
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==== boilerplate
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =================================
|
|
||||||
// === Module Structure Reexport ===
|
|
||||||
// =================================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
use console_error_panic_hook;
|
|
||||||
|
|
||||||
#[wasm_bindgen(start)]
|
|
||||||
pub fn start() {
|
|
||||||
console_error_panic_hook::set_once();
|
|
||||||
set_stdout();
|
|
||||||
println!("----");
|
|
||||||
|
|
||||||
main();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////
|
|
||||||
|
|
||||||
type PrintFn = fn(&str) -> std::io::Result<()>;
|
|
||||||
|
|
||||||
struct Printer {
|
|
||||||
printfn: PrintFn,
|
|
||||||
buffer: String,
|
|
||||||
is_buffered: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Printer {
|
|
||||||
fn new(printfn: PrintFn, is_buffered: bool) -> Printer {
|
|
||||||
Printer {
|
|
||||||
buffer: String::new(),
|
|
||||||
printfn,
|
|
||||||
is_buffered,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::io::Write for Printer {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
|
||||||
self.buffer.push_str(&String::from_utf8_lossy(buf));
|
|
||||||
|
|
||||||
if !self.is_buffered {
|
|
||||||
(self.printfn)(&self.buffer)?;
|
|
||||||
self.buffer.clear();
|
|
||||||
|
|
||||||
return Ok(buf.len());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(i) = self.buffer.rfind('\n') {
|
|
||||||
let buffered = {
|
|
||||||
let (first, last) = self.buffer.split_at(i);
|
|
||||||
(self.printfn)(first)?;
|
|
||||||
|
|
||||||
String::from(&last[1..])
|
|
||||||
};
|
|
||||||
|
|
||||||
self.buffer.clear();
|
|
||||||
self.buffer.push_str(&buffered);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) -> std::io::Result<()> {
|
|
||||||
(self.printfn)(&self.buffer)?;
|
|
||||||
self.buffer.clear();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _print(msg: &str) -> std::io::Result<()> {
|
|
||||||
web_sys::console::info_1(&msg.to_string().into());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn set_stdout() {
|
|
||||||
let printer = Printer::new(_print, true);
|
|
||||||
std::io::set_print(Some(Box::new(printer)));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_stdout_unbuffered() {
|
|
||||||
let printer = Printer::new(_print, false);
|
|
||||||
std::io::set_print(Some(Box::new(printer)));
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "basegl-prelude"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Wojciech Danilo <wojciech.danilo@gmail.com>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
failure = "0.1.5"
|
|
||||||
derive_more = "0.15.0"
|
|
||||||
shrinkwraprs = "0.2.1"
|
|
||||||
itertools = "0.8"
|
|
||||||
derivative = "1.0.3"
|
|
||||||
num = "0.2.0"
|
|
||||||
boolinator = "2.4.0"
|
|
@ -1,58 +0,0 @@
|
|||||||
#![feature(trait_alias)]
|
|
||||||
|
|
||||||
pub use boolinator::Boolinator;
|
|
||||||
pub use core::any::type_name;
|
|
||||||
pub use core::fmt::Debug;
|
|
||||||
pub use derivative::Derivative;
|
|
||||||
pub use derive_more::*;
|
|
||||||
pub use failure::Fail;
|
|
||||||
pub use itertools::Itertools;
|
|
||||||
pub use num::Num;
|
|
||||||
pub use shrinkwraprs::Shrinkwrap;
|
|
||||||
pub use std::cell::Ref;
|
|
||||||
pub use std::cell::RefCell;
|
|
||||||
pub use std::collections::HashMap;
|
|
||||||
pub use std::collections::HashSet;
|
|
||||||
pub use std::convert::identity;
|
|
||||||
pub use std::convert::TryFrom;
|
|
||||||
pub use std::convert::TryInto;
|
|
||||||
pub use std::fmt::Display;
|
|
||||||
pub use std::hash::Hash;
|
|
||||||
pub use std::iter;
|
|
||||||
pub use std::iter::FromIterator;
|
|
||||||
pub use std::marker::PhantomData;
|
|
||||||
pub use std::ops::Deref;
|
|
||||||
pub use std::ops::DerefMut;
|
|
||||||
pub use std::ops::Index;
|
|
||||||
pub use std::ops::IndexMut;
|
|
||||||
pub use std::rc::Rc;
|
|
||||||
pub use std::rc::Weak;
|
|
||||||
pub use std::slice;
|
|
||||||
pub use std::slice::SliceIndex;
|
|
||||||
|
|
||||||
pub trait Str = AsRef<str>;
|
|
||||||
|
|
||||||
pub fn default<T: Default>() -> T {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Derivative)]
|
|
||||||
#[derive(Shrinkwrap)]
|
|
||||||
#[shrinkwrap(mutable)]
|
|
||||||
#[derivative(Clone(bound="T: Clone"))]
|
|
||||||
pub struct WithPhantomType<T, P=()> {
|
|
||||||
#[shrinkwrap(main_field)]
|
|
||||||
pub t: T,
|
|
||||||
phantom: PhantomData<P>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, P> WithPhantomType<T, P> {
|
|
||||||
pub fn new(t: T) -> Self {
|
|
||||||
let phantom = PhantomData;
|
|
||||||
Self { t, phantom }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with<T, F: FnOnce(T) -> Out, Out>(t: T, f: F) -> Out {
|
|
||||||
f(t)
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "structology"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Wojciech Danilo <wojciech.danilo@gmail.com>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
structology-macros = { version = "0.1.0" , path = "../macros" }
|
|
||||||
basegl-prelude = { version = "0.1.0" , path = "../../prelude" }
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
|||||||
#![feature(generators, generator_trait)]
|
|
||||||
|
|
||||||
pub use structology_macros::*;
|
|
||||||
|
|
||||||
use std::ops::Generator;
|
|
||||||
use std::ops::GeneratorState;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use basegl_prelude::PhantomData;
|
|
||||||
|
|
||||||
// ========================
|
|
||||||
// === IterForGenerator ===
|
|
||||||
// ========================
|
|
||||||
|
|
||||||
pub struct IterForGenerator<G: Generator>(pub G);
|
|
||||||
|
|
||||||
impl<G> Iterator for IterForGenerator<G>
|
|
||||||
where G: Generator<Return = ()> + Unpin {
|
|
||||||
type Item = G::Yield;
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
match { Pin::new(&mut self.0).resume() } {
|
|
||||||
GeneratorState::Yielded(element) => Some(element),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ======================
|
|
||||||
// === EmptyGenerator ===
|
|
||||||
// ======================
|
|
||||||
|
|
||||||
pub struct EmptyGenerator<T>(PhantomData<T>);
|
|
||||||
|
|
||||||
impl<T> EmptyGenerator<T> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self(PhantomData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Iterator for EmptyGenerator<T> {
|
|
||||||
type Item = T;
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "structology-macros"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Wojciech Danilo <wojciech.danilo@gmail.com>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
basegl-prelude = { version = "0.1.0" , path = "../../prelude" }
|
|
||||||
proc-macro2 = "1.0"
|
|
||||||
quote = "1.0"
|
|
||||||
Inflector = "0.11.4"
|
|
||||||
itertools = "0.8.1"
|
|
||||||
|
|
||||||
[dependencies.syn]
|
|
||||||
version = "1.0"
|
|
||||||
features = [
|
|
||||||
'extra-traits'
|
|
||||||
]
|
|
@ -1,350 +0,0 @@
|
|||||||
extern crate proc_macro;
|
|
||||||
|
|
||||||
use basegl_prelude::*;
|
|
||||||
|
|
||||||
use inflector::Inflector;
|
|
||||||
use proc_macro2::{TokenStream, Ident, Span};
|
|
||||||
use quote::quote;
|
|
||||||
use syn;
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/// In order to make the definition easier to read, an example expansion of the
|
|
||||||
/// following definition was provided for each quotation:
|
|
||||||
///
|
|
||||||
/// #[derive(Iterator)]
|
|
||||||
/// pub struct Foo<S, T> { foo: T }
|
|
||||||
#[proc_macro_derive(Iterator)]
|
|
||||||
pub fn derive_iterator
|
|
||||||
(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
||||||
let decl = syn::parse_macro_input!(input as syn::DeriveInput);
|
|
||||||
let data = &decl.data;
|
|
||||||
let params = &decl.generics.params.iter().collect::<Vec<_>>();
|
|
||||||
match params.last() {
|
|
||||||
Some(last_param) => derive_iterator_for(&decl, &last_param),
|
|
||||||
None => proc_macro::TokenStream::from(quote! {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn derive_iterator_for
|
|
||||||
( decl : &syn::DeriveInput
|
|
||||||
, target_param : &syn::GenericParam
|
|
||||||
) -> proc_macro::TokenStream {
|
|
||||||
let data = &decl.data;
|
|
||||||
let params = &decl.generics.params.iter().collect::<Vec<_>>();
|
|
||||||
let target_param_str = repr(&target_param);
|
|
||||||
let matched_fields: Vec<TokenStream> = match *data {
|
|
||||||
syn::Data::Struct(ref data) => {
|
|
||||||
fields_list(&data.fields).iter().enumerate().filter_map(|(i, f)| {
|
|
||||||
let type_matched = repr(&f.ty) == target_param_str;
|
|
||||||
type_matched.as_some_from(|| {
|
|
||||||
match &f.ident {
|
|
||||||
Some(ident) => quote!(#ident),
|
|
||||||
None => {
|
|
||||||
let ix = syn::Index::from(i);
|
|
||||||
quote!(#ix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}).collect()
|
|
||||||
}
|
|
||||||
syn::Data::Enum(_) | syn::Data::Union(_) => unimplemented!(),
|
|
||||||
};
|
|
||||||
let data = &decl.ident;
|
|
||||||
let t_iterator = format!("{}Iterator" , data);
|
|
||||||
let t_iterator_mut = format!("{}IteratorMut" , data);
|
|
||||||
let iterator = t_iterator.to_snake_case();
|
|
||||||
let iterator_mut = t_iterator_mut.to_snake_case();
|
|
||||||
let t_iterator = Ident::new(&t_iterator , Span::call_site());
|
|
||||||
let t_iterator_mut = Ident::new(&t_iterator_mut , Span::call_site());
|
|
||||||
let iterator = Ident::new(&iterator , Span::call_site());
|
|
||||||
let iterator_mut = Ident::new(&iterator_mut , Span::call_site());
|
|
||||||
let iter_body_ref = quote! {
|
|
||||||
structology::IterForGenerator
|
|
||||||
(move || { #(yield &t.#matched_fields;)* })
|
|
||||||
};
|
|
||||||
let iter_body_mut = quote! {
|
|
||||||
structology::IterForGenerator
|
|
||||||
(move || { #(yield &mut t.#matched_fields;)* })
|
|
||||||
};
|
|
||||||
let iter_body_dummy = quote! { structology::EmptyGenerator::new() };
|
|
||||||
let empty = matched_fields.is_empty();
|
|
||||||
let iter_body = if empty { &iter_body_dummy } else { &iter_body_ref };
|
|
||||||
let iter_body_mut = if empty { &iter_body_dummy } else { &iter_body_mut };
|
|
||||||
let expanded = quote! {
|
|
||||||
// type FooIterator<'t, T> = impl Iterator<Item = &'t T>;
|
|
||||||
type #t_iterator<'t, #(#params),*> =
|
|
||||||
impl Iterator<Item = &'t #target_param>;
|
|
||||||
|
|
||||||
// pub fn foo_iterator<'t, T>
|
|
||||||
// (t: &'t Foo<T>) -> FooIterator<'t, T> {
|
|
||||||
// structology::IterForGenerator(move || {
|
|
||||||
// yield &t.foo;
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
pub fn #iterator<'t, #(#params),*>
|
|
||||||
(t: &'t #data<#(#params),*>) -> #t_iterator<'t, #(#params),*> {
|
|
||||||
#iter_body
|
|
||||||
}
|
|
||||||
|
|
||||||
// type FooIteratorMut<'t, T> = impl Iterator<Item = &'t mut T>;
|
|
||||||
type #t_iterator_mut<'t, #(#params),*> =
|
|
||||||
impl Iterator<Item = &'t mut #target_param>;
|
|
||||||
|
|
||||||
// pub fn foo_iterator_mut<'t, T>
|
|
||||||
// (t: &'t mut Foo<T>) -> FooIteratorMut<'t, T> {
|
|
||||||
// structology::IterForGenerator(move || {
|
|
||||||
// yield &t.foo;
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
pub fn #iterator_mut<'t, #(#params),*>
|
|
||||||
(t: &'t mut #data<#(#params),*>) -> #t_iterator_mut<'t, #(#params),*> {
|
|
||||||
#iter_body_mut
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl<'t, T> IntoIterator for &'t Foo<T> {
|
|
||||||
// type Item = &'t T;
|
|
||||||
// type IntoIter = FooIterator<'t, T>;
|
|
||||||
// fn into_iter(self) -> FooIterator<'t, T> {
|
|
||||||
// foo_iterator(self)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
impl<'t, #(#params),*> IntoIterator for &'t #data<#(#params),*> {
|
|
||||||
type Item = &'t #target_param;
|
|
||||||
type IntoIter = #t_iterator<'t, #(#params),*>;
|
|
||||||
fn into_iter(self) -> #t_iterator<'t, #(#params),*> {
|
|
||||||
#iterator(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl<'t, T> IntoIterator for &'t mut Foo<T> {
|
|
||||||
// type Item = &'t mut T;
|
|
||||||
// type IntoIter = FooIteratorMut<'t, T>;
|
|
||||||
// fn into_iter(self) -> FooIteratorMut<'t, T> {
|
|
||||||
// foo_iterator_mut(self)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
impl<'t, #(#params),*> IntoIterator for &'t mut #data<#(#params),*> {
|
|
||||||
type Item = &'t mut #target_param;
|
|
||||||
type IntoIter = #t_iterator_mut<'t, #(#params),*>;
|
|
||||||
fn into_iter(self) -> #t_iterator_mut<'t, #(#params),*> {
|
|
||||||
#iterator_mut(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl Foo<T> {
|
|
||||||
// pub fn iter(&self) -> FooIterator<'_, T> {
|
|
||||||
// #foo_iterator(self)
|
|
||||||
// }
|
|
||||||
// pub fn iter_mut(&mut self) -> FooIteratorMut<'_, T> {
|
|
||||||
// #foo_iterator_mut (self)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
impl<#(#params),*> #data<#(#params),*> {
|
|
||||||
pub fn iter(&self) -> #t_iterator<'_, #(#params),*> {
|
|
||||||
#iterator(self)
|
|
||||||
}
|
|
||||||
pub fn iter_mut(&mut self) -> #t_iterator_mut<'_, #(#params),*> {
|
|
||||||
#iterator_mut(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
proc_macro::TokenStream::from(expanded)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fields_list(fields: &syn::Fields) -> Vec<&syn::Field> {
|
|
||||||
match fields {
|
|
||||||
syn::Fields::Named (ref f) => { f.named.iter().collect() }
|
|
||||||
syn::Fields::Unnamed (ref f) => { f.unnamed.iter().collect() }
|
|
||||||
syn::Fields::Unit => default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn field_type(field: &syn::Field) -> String {
|
|
||||||
let tp = &field.ty;
|
|
||||||
quote!(#tp).to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro_derive(AstNode)]
|
|
||||||
pub fn derive_ast_node
|
|
||||||
(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
||||||
let expanded = quote! {
|
|
||||||
#[derive(Debug)]
|
|
||||||
};
|
|
||||||
proc_macro::TokenStream::from(expanded)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn ast_node
|
|
||||||
(_meta: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
||||||
let input: TokenStream = input.into();
|
|
||||||
let output = quote! {
|
|
||||||
#[derive(Eq, PartialEq, Debug)]
|
|
||||||
#[derive(Iterator)]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#input
|
|
||||||
};
|
|
||||||
output.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn ast
|
|
||||||
( attrs : proc_macro::TokenStream
|
|
||||||
, input : proc_macro::TokenStream
|
|
||||||
) -> proc_macro::TokenStream {
|
|
||||||
let attrs: TokenStream = attrs.into();
|
|
||||||
let decl = syn::parse_macro_input!(input as syn::DeriveInput);
|
|
||||||
let output = match &decl.data {
|
|
||||||
syn::Data::Enum { .. } => quote! {
|
|
||||||
#[to_variant_types(#attrs)]
|
|
||||||
#[ast_node]
|
|
||||||
#decl
|
|
||||||
},
|
|
||||||
_ => quote! {
|
|
||||||
#[ast_node]
|
|
||||||
#decl
|
|
||||||
}
|
|
||||||
};
|
|
||||||
output.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn repr<T: quote::ToTokens>(t: &T) -> String {
|
|
||||||
quote!(#t).to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
use syn::visit::{self, Visit};
|
|
||||||
use syn::{File, ItemFn};
|
|
||||||
|
|
||||||
struct TypeGather {
|
|
||||||
pub types: Vec<String>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TypeGather {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let types = default();
|
|
||||||
Self { types }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ast> Visit<'ast> for TypeGather {
|
|
||||||
fn visit_type_path(&mut self, node: &'ast syn::TypePath) {
|
|
||||||
self.types.push(repr(node));
|
|
||||||
visit::visit_type_path(self, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gather_all_types(node: &syn::Type) -> Vec<String> {
|
|
||||||
let mut type_gather = TypeGather::new();
|
|
||||||
type_gather.visit_type(node);
|
|
||||||
type_gather.types
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn mk_product_type
|
|
||||||
( is_flat : bool
|
|
||||||
, decl : &syn::DeriveInput
|
|
||||||
, variant : &syn::Variant
|
|
||||||
) -> syn::ItemStruct {
|
|
||||||
use syn::ItemStruct;
|
|
||||||
let fields = &variant.fields;
|
|
||||||
let types = fields.iter().flat_map(|f| {gather_all_types(&f.ty) });
|
|
||||||
let types = types.collect::<HashSet<_>>();
|
|
||||||
let ty_vars = decl.generics.params.iter().cloned();
|
|
||||||
let params = ty_vars.filter(|v| types.contains(&repr(&v))).collect();
|
|
||||||
let attrs = decl.attrs.clone();
|
|
||||||
let vis = decl.vis.clone();
|
|
||||||
let struct_token = syn::token::Struct { span: Span::call_site() };
|
|
||||||
let ident_flat = variant.ident.clone();
|
|
||||||
let ident_nested = format!("{}{}", decl.ident, variant.ident);
|
|
||||||
let ident_nested = Ident::new(&ident_nested, Span::call_site());
|
|
||||||
let ident = if is_flat { ident_flat } else { ident_nested };
|
|
||||||
let generics = syn::Generics { params, .. default() };
|
|
||||||
let mut fields = variant.fields.clone();
|
|
||||||
let semi_token = None;
|
|
||||||
fields.iter_mut().for_each(|f| f.vis = vis.clone());
|
|
||||||
ItemStruct { attrs, vis, struct_token, ident, generics, fields, semi_token }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_variant_decl
|
|
||||||
(ident: &syn::Ident, variant: &syn::ItemStruct) -> TokenStream {
|
|
||||||
let variant_ident = &variant.ident;
|
|
||||||
let params = variant.generics.params.iter();
|
|
||||||
quote! {
|
|
||||||
// App(ShapeApp<T>),
|
|
||||||
// Var(ShapeVar),
|
|
||||||
#ident(#variant_ident<#(#params),*>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_from_impls
|
|
||||||
(ident: &syn::Ident, decl: &syn::DeriveInput, variant: &syn::ItemStruct) -> TokenStream {
|
|
||||||
let sum_label = &decl.ident;
|
|
||||||
let variant_label = &variant.ident;
|
|
||||||
let sum_params = &decl.generics.params.iter().cloned().collect::<Vec<_>>();
|
|
||||||
let variant_params = &variant.generics.params.iter().cloned().collect::<Vec<_>>();
|
|
||||||
;
|
|
||||||
quote! {
|
|
||||||
// impl<T> From<App<T>> for Shape<T> {
|
|
||||||
// fn from(t: App<T>) -> Self { Shape::App(t) }
|
|
||||||
// }
|
|
||||||
// ...
|
|
||||||
impl<#(#sum_params),*> From<#variant_label<#(#variant_params),*>>
|
|
||||||
for #sum_label<#(#sum_params),*> {
|
|
||||||
fn from(t: #variant_label<#(#variant_params),*>) -> Self {
|
|
||||||
#sum_label::#ident(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// In order to make the definition easier to read, an example expansion of the
|
|
||||||
/// following definition was provided for each quotation:
|
|
||||||
///
|
|
||||||
/// #[to_variant_types]
|
|
||||||
/// pub enum Shape<T> {
|
|
||||||
/// Var(Var),
|
|
||||||
/// App(App<T>),
|
|
||||||
/// }
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn to_variant_types
|
|
||||||
( attrs: proc_macro::TokenStream
|
|
||||||
, input: proc_macro::TokenStream
|
|
||||||
) -> proc_macro::TokenStream {
|
|
||||||
let attrs: TokenStream = attrs.into();
|
|
||||||
let decl = syn::parse_macro_input!(input as syn::DeriveInput);
|
|
||||||
let ident = &decl.ident;
|
|
||||||
let ty_vars = &decl.generics.params;
|
|
||||||
let variants = match &decl.data {
|
|
||||||
syn::Data::Enum(ref data) => data.variants.iter(),
|
|
||||||
_ => unimplemented!()
|
|
||||||
}.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let is_flat = repr(&attrs) == "flat";
|
|
||||||
let variant_idents = variants.iter().map(|v| &v.ident).collect::<Vec<_>>();
|
|
||||||
let structs = variants.iter().map(|v| mk_product_type(is_flat, &decl, v));
|
|
||||||
let structs = structs.collect::<Vec<_>>();
|
|
||||||
let variant_decls = variant_idents.iter().zip(structs.iter()).map(|(i,v)| gen_variant_decl(i,&v));
|
|
||||||
let variant_froms = variant_idents.iter().zip(structs.iter()).map(|(i,v)| gen_from_impls(i, &decl, &v));
|
|
||||||
|
|
||||||
// Handle single value, unnamed params as created by user.
|
|
||||||
let structs = structs.iter().filter(|v| match &v.fields {
|
|
||||||
syn::Fields::Unnamed(f) => f.unnamed.len() != 1,
|
|
||||||
_ => true
|
|
||||||
});
|
|
||||||
|
|
||||||
let output = quote! {
|
|
||||||
#[derive(Eq, PartialEq, Debug)]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub enum #ident <#ty_vars> {
|
|
||||||
#(#variant_decls),*
|
|
||||||
}
|
|
||||||
#(#structs)*
|
|
||||||
#(#variant_froms)*
|
|
||||||
};
|
|
||||||
output.into()
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "basegl-system-web"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Wojciech Danilo <wojciech.danilo@gmail.com>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["console_error_panic_hook"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
basegl-prelude = { version = "0.1.0" , path = "../../prelude" }
|
|
||||||
js-sys = { version = "0.3.28" }
|
|
||||||
wasm-bindgen = { version = "^0.2" , features = ["nightly"] }
|
|
||||||
failure = { version = "0.1.5" }
|
|
||||||
|
|
||||||
console_error_panic_hook = { version = "0.1.1", optional = true }
|
|
||||||
|
|
||||||
[dependencies.web-sys]
|
|
||||||
version = "0.3.4"
|
|
||||||
features = [
|
|
||||||
'Document',
|
|
||||||
'Element',
|
|
||||||
'HtmlCanvasElement',
|
|
||||||
'WebGlBuffer',
|
|
||||||
'WebGlRenderingContext',
|
|
||||||
'WebGlProgram',
|
|
||||||
'WebGlShader',
|
|
||||||
'Window',
|
|
||||||
'console'
|
|
||||||
]
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
wasm-bindgen-test = "0.2"
|
|
@ -1,72 +0,0 @@
|
|||||||
// ==============
|
|
||||||
// === IxPool ===
|
|
||||||
// ==============
|
|
||||||
|
|
||||||
class IxPool {
|
|
||||||
constructor() {
|
|
||||||
this.next = 0
|
|
||||||
this.free = []
|
|
||||||
}
|
|
||||||
|
|
||||||
reserve() {
|
|
||||||
let ix
|
|
||||||
if(this.free.length == 0) {
|
|
||||||
ix = this.next
|
|
||||||
this.next += 1
|
|
||||||
} else {
|
|
||||||
ix = this.free.shift()
|
|
||||||
}
|
|
||||||
return ix
|
|
||||||
}
|
|
||||||
|
|
||||||
drop(ix) {
|
|
||||||
this.free.unshift(ix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ============
|
|
||||||
// === Pool ===
|
|
||||||
// ============
|
|
||||||
|
|
||||||
class Pool {
|
|
||||||
constructor(cons) {
|
|
||||||
this.cons = cons
|
|
||||||
this.ixs = new IxPool
|
|
||||||
}
|
|
||||||
|
|
||||||
reserve(...args) {
|
|
||||||
let ix = this.ixs.reserve()
|
|
||||||
this[ix] = this.cons(...args)
|
|
||||||
return ix
|
|
||||||
}
|
|
||||||
|
|
||||||
drop(ix) {
|
|
||||||
this.ixs.drop(ix)
|
|
||||||
this[ix] = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ======================
|
|
||||||
// === ResizeObserver ===
|
|
||||||
// ======================
|
|
||||||
|
|
||||||
let resizeObserverPool = new Pool((...args) => new ResizeObserver(...args))
|
|
||||||
|
|
||||||
export function resize_observe(target, f) {
|
|
||||||
let id = resizeObserverPool.reserve(resize_observer_update(f))
|
|
||||||
resizeObserverPool[id].observe(target)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resize_unobserve(id) {
|
|
||||||
resizeObserverPool[id].disconnect()
|
|
||||||
resizeObserverPool.drop(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
function resize_observer_update(f) {
|
|
||||||
return entries => {
|
|
||||||
let rect = entries[0].contentRect;
|
|
||||||
f(rect.width, rect.height);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,196 +0,0 @@
|
|||||||
#![feature(trait_alias)]
|
|
||||||
|
|
||||||
pub mod resize_observer;
|
|
||||||
|
|
||||||
use basegl_prelude::*;
|
|
||||||
|
|
||||||
use wasm_bindgen::prelude::Closure;
|
|
||||||
use wasm_bindgen::JsCast;
|
|
||||||
use wasm_bindgen::JsValue;
|
|
||||||
use web_sys::HtmlCanvasElement;
|
|
||||||
use web_sys::WebGlRenderingContext;
|
|
||||||
|
|
||||||
pub use web_sys::console;
|
|
||||||
|
|
||||||
// =============
|
|
||||||
// === Error ===
|
|
||||||
// =============
|
|
||||||
|
|
||||||
type Result<A> = std::result::Result<A, Error>;
|
|
||||||
|
|
||||||
#[derive(Debug, Fail)]
|
|
||||||
pub enum Error {
|
|
||||||
#[fail(display = "Missing `{}`.", name)]
|
|
||||||
Missing { name: String },
|
|
||||||
#[fail(display = "Type mismatch. Expected `{}`, got `{}`.", expected, got)]
|
|
||||||
TypeMismatch { expected: String, got: String },
|
|
||||||
#[fail(display = "WebGL {} is not available.", version)]
|
|
||||||
NoWebGL { version: u32 },
|
|
||||||
}
|
|
||||||
impl Error {
|
|
||||||
pub fn missing(name: &str) -> Error {
|
|
||||||
let name = name.to_string();
|
|
||||||
Error::Missing { name }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_mismatch(expected: &str, got: &str) -> Error {
|
|
||||||
let expected = expected.to_string();
|
|
||||||
let got = got.to_string();
|
|
||||||
Error::TypeMismatch { expected, got }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==============
|
|
||||||
// === LogMsg ===
|
|
||||||
// ==============
|
|
||||||
|
|
||||||
pub trait LogMsg {
|
|
||||||
fn with_log_msg<F: FnOnce(&str) -> T, T>(&self, f: F) -> T;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LogMsg for &str {
|
|
||||||
fn with_log_msg<F: FnOnce(&str) -> T, T>(&self, f: F) -> T {
|
|
||||||
f(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Fn() -> S, S: AsRef<str>> LogMsg for F {
|
|
||||||
fn with_log_msg<G: FnOnce(&str) -> T, T>(&self, f: G) -> T {
|
|
||||||
f(self().as_ref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==============
|
|
||||||
// === Logger ===
|
|
||||||
// ==============
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Logger {
|
|
||||||
pub path: String,
|
|
||||||
}
|
|
||||||
impl Logger {
|
|
||||||
pub fn new<T: AsRef<str>>(path: T) -> Self {
|
|
||||||
let path = path.as_ref().to_string();
|
|
||||||
Self { path }
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Default
|
|
||||||
pub fn new_() -> Self {
|
|
||||||
Self::new("")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sub<T: AsRef<str>>(&self, path: T) -> Self {
|
|
||||||
Self::new(format!("{}.{}", self.path, path.as_ref()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trace<M: LogMsg>(&self, msg: M) {
|
|
||||||
console::debug_1(&self.format(msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn info<M: LogMsg>(&self, msg: M) {
|
|
||||||
// console::info_1(&self.format(msg));
|
|
||||||
console::group_1(&self.format(msg));
|
|
||||||
console::group_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn warning<M: LogMsg>(&self, msg: M) {
|
|
||||||
console::warn_1(&self.format(msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn error<M: LogMsg>(&self, msg: M) {
|
|
||||||
console::error_1(&self.format(msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn group_begin<M: LogMsg>(&self, msg: M) {
|
|
||||||
console::group_1(&self.format(msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn group_end(&self) {
|
|
||||||
console::group_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn group<M: LogMsg, T, F: FnOnce() -> T>(&self, msg: M, f: F) -> T {
|
|
||||||
self.group_begin(msg);
|
|
||||||
let out = f();
|
|
||||||
self.group_end();
|
|
||||||
out
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format<M: LogMsg>(&self, msg: M) -> JsValue {
|
|
||||||
msg.with_log_msg(|s| format!("[{}] {}", self.path, s)).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Logger {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ====================
|
|
||||||
// === Logger Utils ===
|
|
||||||
// ====================
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! fmt {
|
|
||||||
($($arg:tt)*) => (||(format!($($arg)*)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! group {
|
|
||||||
($logger:expr, $message:expr, $body:tt) => {{
|
|
||||||
$logger.group_begin(|| $message);
|
|
||||||
let out = $body;
|
|
||||||
$logger.group_end();
|
|
||||||
out
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===================
|
|
||||||
// === DOM Helpers ===
|
|
||||||
// ===================
|
|
||||||
|
|
||||||
pub fn window() -> Result<web_sys::Window> {
|
|
||||||
web_sys::window().ok_or_else(|| Error::missing("window"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn document() -> Result<web_sys::Document> {
|
|
||||||
window()?.document().ok_or_else(|| Error::missing("document"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_element_by_id(id: &str) -> Result<web_sys::Element> {
|
|
||||||
document()?.get_element_by_id(id).ok_or_else(|| Error::missing(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_element_by_id_as<T: wasm_bindgen::JsCast>(id: &str) -> Result<T> {
|
|
||||||
let elem = get_element_by_id(id)?;
|
|
||||||
let expected = type_name::<T>(); // fixme
|
|
||||||
let got = format!("{:?}", elem); // fixme
|
|
||||||
elem.dyn_into().map_err(|_| Error::type_mismatch(&expected, &got))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_canvas(id: &str) -> Result<web_sys::HtmlCanvasElement> {
|
|
||||||
get_element_by_id_as(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_webgl_context(
|
|
||||||
canvas: &HtmlCanvasElement,
|
|
||||||
version: u32,
|
|
||||||
) -> Result<WebGlRenderingContext>
|
|
||||||
{
|
|
||||||
let no_webgl = || Error::NoWebGL { version };
|
|
||||||
let name_sfx = if version == 1 { "".to_string() } else { version.to_string() };
|
|
||||||
let name = &format!("webgl{}", &name_sfx);
|
|
||||||
let context = canvas.get_context(name).map_err(|_| no_webgl())?.ok_or_else(no_webgl)?;
|
|
||||||
context.dyn_into().map_err(|_| no_webgl())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_animation_frame(f: &Closure<dyn FnMut()>) -> Result<i32> {
|
|
||||||
let req = window()?.request_animation_frame(f.as_ref().unchecked_ref());
|
|
||||||
req.map_err(|_| Error::missing("requestAnimationFrame"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cancel_animation_frame(id: i32) -> Result<()> {
|
|
||||||
let req = window()?.cancel_animation_frame(id);
|
|
||||||
req.map_err(|_| Error::missing("cancel_animation_frame"))
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
use wasm_bindgen::prelude::wasm_bindgen;
|
|
||||||
use wasm_bindgen::prelude::Closure;
|
|
||||||
use wasm_bindgen::JsValue;
|
|
||||||
|
|
||||||
// =============
|
|
||||||
// === Types ===
|
|
||||||
// =============
|
|
||||||
|
|
||||||
pub type Listener = Closure<dyn FnMut(i32, i32)>;
|
|
||||||
|
|
||||||
// ===================
|
|
||||||
// === JS Bindings ===
|
|
||||||
// ===================
|
|
||||||
|
|
||||||
#[wasm_bindgen(module = "/js/resize_observer.js")]
|
|
||||||
extern "C" {
|
|
||||||
fn resize_observe(target: &JsValue, closure: &Listener) -> usize;
|
|
||||||
fn resize_unobserve(id: usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======================
|
|
||||||
// === ResizeObserver ===
|
|
||||||
// ======================
|
|
||||||
|
|
||||||
/// The ResizeObserver interface reports changes to the dimensions of an
|
|
||||||
/// DOM Element's content or border box. ResizeObserver avoids infinite callback
|
|
||||||
/// loops and cyclic dependencies that are often created when resizing via a
|
|
||||||
/// callback function. It does this by only processing elements deeper in the
|
|
||||||
/// DOM in subsequent frames.
|
|
||||||
///
|
|
||||||
/// See also https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ResizeObserver {
|
|
||||||
pub target: JsValue,
|
|
||||||
pub listener: Listener,
|
|
||||||
pub observer_id: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResizeObserver {
|
|
||||||
pub fn new(target: &JsValue, listener: Listener) -> Self {
|
|
||||||
let target = target.clone();
|
|
||||||
let observer_id = resize_observe(&target, &listener);
|
|
||||||
Self { target, listener, observer_id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for ResizeObserver {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
resize_unobserve(self.observer_id);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
wasm-pack build --out-dir '../../target/web' lib/core
|
|
@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
cargo clean -p basegl -p basegl-backend-webgl -p basegl-prelude -p basegl-system-web
|
|
||||||
cargo clippy -- -D warnings
|
|
@ -1,2 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
cargo watch -i .gitignore -i "pkg/*" -s "script/build.sh"
|
|
@ -1,13 +0,0 @@
|
|||||||
//! Test suite for the Web and headless browsers.
|
|
||||||
|
|
||||||
#![cfg(target_arch = "wasm32")]
|
|
||||||
|
|
||||||
extern crate wasm_bindgen_test;
|
|
||||||
use wasm_bindgen_test::*;
|
|
||||||
|
|
||||||
wasm_bindgen_test_configure!(run_in_browser);
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn pass() {
|
|
||||||
assert_eq!(1 + 1, 2);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user