mirror of
https://github.com/enso-org/enso.git
synced 2024-12-24 13:31:41 +03:00
Remove shared libraries from the IDE repo (https://github.com/enso-org/ide/pull/626)
1. Removes `prelude`, and renames it to `enso-prelude`.
2. Removes `shapely`, and renames it to `enso-shapely`.
3. Removes `macro-utils` and renames it to `enso-macro-utils`.
Original commit: a5069c1ae5
This commit is contained in:
parent
0df765dcd5
commit
566a318a91
1
gui/.gitignore
vendored
1
gui/.gitignore
vendored
@ -19,3 +19,4 @@ wasm-pack.log
|
||||
|
||||
# JavaScript
|
||||
node_modules
|
||||
.nvmrc
|
||||
|
142
gui/src/rust/Cargo.lock
generated
142
gui/src/rust/Cargo.lock
generated
@ -47,13 +47,13 @@ dependencies = [
|
||||
"ast-macros 0.1.0",
|
||||
"data 0.1.0",
|
||||
"derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-shapely 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shapely 0.1.0",
|
||||
"shrinkwraprs 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utils 0.1.0",
|
||||
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -64,8 +64,8 @@ name = "ast-macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"Inflector 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-prelude 0.1.0",
|
||||
"macro-utils 0.1.0",
|
||||
"enso-macro-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -308,7 +308,7 @@ dependencies = [
|
||||
name = "code-builder"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -439,7 +439,7 @@ dependencies = [
|
||||
name = "data"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -547,7 +547,7 @@ dependencies = [
|
||||
name = "enso-callback"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -556,7 +556,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-callback 0.1.0",
|
||||
"enso-generics 0.1.0",
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ensogl-system-web 0.1.0",
|
||||
"keyboard-types 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nalgebra 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -570,6 +570,16 @@ dependencies = [
|
||||
"nalgebra 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enso-macro-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enso-math"
|
||||
version = "0.1.0"
|
||||
@ -582,11 +592,13 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "enso-prelude"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"boolinator 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derivative 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive_more 0.99.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enclose 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-shapely 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ifmt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -594,7 +606,6 @@ dependencies = [
|
||||
"nalgebra 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"paste 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shapely 0.1.0",
|
||||
"shrinkwraprs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -609,7 +620,8 @@ dependencies = [
|
||||
"bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"data 0.1.0",
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-shapely 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ensogl-build-utilities 0.1.0",
|
||||
"ensogl-system-web 0.1.0",
|
||||
"failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -624,7 +636,6 @@ dependencies = [
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shapely 0.1.0",
|
||||
"tokio 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utils 0.1.0",
|
||||
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -633,6 +644,31 @@ dependencies = [
|
||||
"zip-extensions 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enso-shapely"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"derivative 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-shapely-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"paste 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shrinkwraprs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enso-shapely-macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"Inflector 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"boolinator 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-macro-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ensogl"
|
||||
version = "0.1.0"
|
||||
@ -647,7 +683,8 @@ dependencies = [
|
||||
"enso-frp 0.1.0",
|
||||
"enso-generics 0.1.0",
|
||||
"enso-math 0.1.0",
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-shapely 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ensogl-core-embedded-fonts 0.1.0",
|
||||
"ensogl-core-msdf-sys 0.1.0",
|
||||
"ensogl-system-web 0.1.0",
|
||||
@ -663,7 +700,6 @@ dependencies = [
|
||||
"optics 0.1.0",
|
||||
"paste 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shapely 0.1.0",
|
||||
"shrinkwraprs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -685,7 +721,7 @@ dependencies = [
|
||||
name = "ensogl-core-embedded-fonts"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ensogl-build-utilities 0.1.0",
|
||||
"zip 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -694,7 +730,7 @@ dependencies = [
|
||||
name = "ensogl-core-msdf-sys"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ensogl-build-utilities 0.1.0",
|
||||
"ensogl-core-embedded-fonts 0.1.0",
|
||||
"futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -711,7 +747,7 @@ dependencies = [
|
||||
"async-std 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"data 0.1.0",
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gloo-timers 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -795,13 +831,6 @@ dependencies = [
|
||||
"miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flexer"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flo_stream"
|
||||
version = "0.4.0"
|
||||
@ -1011,14 +1040,14 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"ast 0.1.0",
|
||||
"enso-frp 0.1.0",
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-shapely 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ensogl 0.1.0",
|
||||
"js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"logger 0.1.0",
|
||||
"nalgebra 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shapely 0.1.0",
|
||||
"span-tree 0.1.0",
|
||||
"wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1030,7 +1059,8 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"ast 0.1.0",
|
||||
"enso-frp 0.1.0",
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-shapely 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ensogl 0.1.0",
|
||||
"ensogl-core-msdf-sys 0.1.0",
|
||||
"ensogl-system-web 0.1.0",
|
||||
@ -1040,7 +1070,6 @@ dependencies = [
|
||||
"js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nalgebra 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shapely 0.1.0",
|
||||
"span-tree 0.1.0",
|
||||
"wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1251,8 +1280,9 @@ dependencies = [
|
||||
"data 0.1.0",
|
||||
"enso-callback 0.1.0",
|
||||
"enso-frp 0.1.0",
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-protocol 0.1.0",
|
||||
"enso-shapely 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ensogl 0.1.0",
|
||||
"ensogl-core-msdf-sys 0.1.0",
|
||||
"ensogl-system-web 0.1.0",
|
||||
@ -1268,7 +1298,6 @@ dependencies = [
|
||||
"regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shapely 0.1.0",
|
||||
"span-tree 0.1.0",
|
||||
"utils 0.1.0",
|
||||
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1386,13 +1415,13 @@ dependencies = [
|
||||
name = "json-rpc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-shapely 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ensogl-system-web 0.1.0",
|
||||
"failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shapely 0.1.0",
|
||||
"shrinkwraprs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utils 0.1.0",
|
||||
]
|
||||
@ -1477,21 +1506,12 @@ dependencies = [
|
||||
name = "logger"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-prelude 0.1.0",
|
||||
"shapely 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-shapely 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macro-utils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
@ -1830,7 +1850,7 @@ dependencies = [
|
||||
name = "optics"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1887,7 +1907,7 @@ dependencies = [
|
||||
"bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"data 0.1.0",
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ensogl-build-utilities 0.1.0",
|
||||
"failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2477,30 +2497,6 @@ dependencies = [
|
||||
"opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shapely"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"derivative 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enso-prelude 0.1.0",
|
||||
"paste 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shapely-macros 0.1.0",
|
||||
"shrinkwraprs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shapely-macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"Inflector 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"boolinator 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"macro-utils 0.1.0",
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shrinkwraprs"
|
||||
version = "0.2.3"
|
||||
@ -2574,7 +2570,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"ast 0.1.0",
|
||||
"data 0.1.0",
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parser 0.1.0",
|
||||
"utils 0.1.0",
|
||||
@ -2973,7 +2969,7 @@ dependencies = [
|
||||
name = "utils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3156,7 +3152,7 @@ dependencies = [
|
||||
name = "web-test"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-prelude 0.1.0",
|
||||
"enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ensogl 0.1.0",
|
||||
"ensogl-system-web 0.1.0",
|
||||
"js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3335,6 +3331,10 @@ dependencies = [
|
||||
"checksum enclose 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1056f553da426e9c025a662efa48b52e62e0a3a7648aa2d15aeaaf7f0d329357"
|
||||
"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
"checksum encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28"
|
||||
"checksum enso-macro-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87d75170551105f0c13e78f403f38173e428f04b921228deabb53367bb968dfa"
|
||||
"checksum enso-prelude 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "663f055d5fa5e359d81069ff69d31a74da59086d0fa8ec7ef933bb9fdf0a07e2"
|
||||
"checksum enso-shapely 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a1741af8785f986ba930c9dc052c1a7bc6c223b573801e33667467615dddf09b"
|
||||
"checksum enso-shapely-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddab3b8e1a9a16e57fe49e25afbbe2e3215208ab040831bc004d78208227ca14"
|
||||
"checksum enum_dispatch 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "733967190e01b0dcb64f2f42687a78af0e418e064489e993e16445643d088560"
|
||||
"checksum error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd"
|
||||
"checksum failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
|
||||
|
@ -20,16 +20,11 @@ members = [
|
||||
"lib/debug-scenes",
|
||||
"lib/graph-editor",
|
||||
"lib/eval-tt",
|
||||
"lib/flexer",
|
||||
"lib/frp",
|
||||
"lib/generics",
|
||||
"lib/logger",
|
||||
"lib/macro-utils",
|
||||
"lib/math",
|
||||
"lib/optics",
|
||||
"lib/prelude",
|
||||
"lib/shapely/impl",
|
||||
"lib/shapely/macros",
|
||||
"lib/system/web",
|
||||
]
|
||||
|
||||
|
@ -17,7 +17,7 @@ enso-callback = { version = "0.1.0" , path = "../lib/callback"
|
||||
ensogl-core-embedded-fonts = { version = "0.1.0" , path = "embedded-fonts" }
|
||||
ensogl-core-msdf-sys = { version = "0.1.0" , path = "msdf-sys" }
|
||||
enso-generics = { version = "0.1.0" , path = "../lib/generics" }
|
||||
enso-prelude = { version = "0.1.0" , path = "../lib/prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
ensogl-system-web = { version = "0.1.0" , path = "../lib/system/web" }
|
||||
code-builder = { version = "0.1.0" , path = "../lib/code-builder" }
|
||||
data = { version = "0.1.0" , path = "../lib/data" }
|
||||
@ -26,7 +26,7 @@ enso-math = { version = "0.1.0" , path = "../lib/math"
|
||||
eval-tt = { version = "0.1.0" , path = "../lib/eval-tt" }
|
||||
logger = { version = "0.1.0" , path = "../lib/logger" }
|
||||
optics = { version = "0.1.0" , path = "../lib/optics" }
|
||||
shapely = { version = "0.1.0" , path = "../lib/shapely/impl" }
|
||||
enso-shapely = { version = "0.1.0" }
|
||||
|
||||
bit_field = { version = "0.10.0" }
|
||||
console_error_panic_hook = { version = "0.1.6" }
|
||||
|
@ -10,7 +10,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
enso-prelude = { version = "0.1.0", path="../../lib/prelude"}
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
|
||||
[build-dependencies]
|
||||
ensogl-build-utilities = { version = "0.1.0", path = "../../build" }
|
||||
|
@ -11,7 +11,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
wasm-bindgen = { version = "=0.2.58" }
|
||||
js-sys = { version = "0.3.30" }
|
||||
nalgebra = { version = "0.21.1" }
|
||||
enso-prelude = { version = "0.1.0", path="../../lib/prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = { version = "0.3.8" }
|
||||
|
@ -49,7 +49,7 @@ macro_rules! define_color_space {
|
||||
}
|
||||
|
||||
impl HasComponentsRepr for $data_name{
|
||||
type ComponentsRepr = ($(shapely::replace!($comp,f32)),*,);
|
||||
type ComponentsRepr = ($(enso_shapely::replace!($comp,f32)),*,);
|
||||
}
|
||||
|
||||
impl From<$data_name> for ComponentsOf<$data_name> {
|
||||
|
@ -10,7 +10,7 @@ use crate::system::gpu::shader::Context;
|
||||
|
||||
use num_enum::IntoPrimitive;
|
||||
|
||||
use shapely::shared;
|
||||
use enso_shapely::shared;
|
||||
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ use crate::control::callback::CallbackFn;
|
||||
|
||||
use web_sys::WebGlProgram;
|
||||
|
||||
use shapely::shared;
|
||||
use enso_shapely::shared;
|
||||
|
||||
|
||||
|
||||
|
@ -67,9 +67,9 @@ pub mod prelude {
|
||||
pub use logger::*;
|
||||
pub use logger::AnyLogger;
|
||||
pub use logger::disabled::Logger;
|
||||
pub use shapely::CloneRef;
|
||||
pub use shapely::newtype_copy;
|
||||
pub use shapely::shared;
|
||||
pub use enso_shapely::CloneRef;
|
||||
pub use enso_shapely::newtype_copy;
|
||||
pub use enso_shapely::shared;
|
||||
pub use super::display::traits::*;
|
||||
pub use super::data::container::AddMut;
|
||||
pub use super::math::types::*;
|
||||
|
@ -26,7 +26,7 @@ use nalgebra::Matrix4;
|
||||
use nalgebra::Vector2;
|
||||
use nalgebra::Vector3;
|
||||
use nalgebra::Vector4;
|
||||
use shapely::shared;
|
||||
use enso_shapely::shared;
|
||||
use std::iter::Extend;
|
||||
use std::ops::RangeInclusive;
|
||||
use web_sys::WebGlBuffer;
|
||||
|
@ -65,7 +65,7 @@ pub mod traits {
|
||||
#[macro_export]
|
||||
macro_rules! define_singletons_gl {
|
||||
( $target:tt $( $(#$meta:tt)* $name:ident = $expr:expr ),* $(,)? ) => {
|
||||
shapely::define_singletons!{ $( $(#$meta)* $name),* }
|
||||
enso_shapely::define_singletons!{ $( $(#$meta)* $name),* }
|
||||
$crate::define_gl_enum_conversions!{ $target $( $(#$meta)* $name = $expr ),* }
|
||||
}
|
||||
}
|
||||
@ -127,7 +127,7 @@ macro_rules! define_singleton_enum_gl_from {
|
||||
$( $(#$field_meta:tt)* $field:ident),* $(,)?
|
||||
}
|
||||
) => {
|
||||
shapely::define_singleton_enum_from! { $(#$meta)* $name {$($(#$field_meta)* $field),*}}
|
||||
enso_shapely::define_singleton_enum_from! { $(#$meta)* $name {$($(#$field_meta)* $field),*}}
|
||||
|
||||
impl From<&$name> for $($target)* {
|
||||
fn from(t:&$name) -> Self {
|
||||
|
@ -28,6 +28,6 @@ pub trait StorageRelation<InternalFormat,ElemType>: Storage {
|
||||
type Storage: Debug;
|
||||
}
|
||||
|
||||
shapely::define_singleton_enum! {
|
||||
enso_shapely::define_singleton_enum! {
|
||||
AnyStorage {RemoteImage,GpuOnly,Owned}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ pub mod upload;
|
||||
use crate::prelude::*;
|
||||
|
||||
use enum_dispatch::*;
|
||||
use shapely::shared;
|
||||
use enso_shapely::shared;
|
||||
use upload::UniformUpload;
|
||||
use web_sys::WebGlUniformLocation;
|
||||
|
||||
|
@ -11,7 +11,7 @@ use crate::math::topology::unit::*;
|
||||
|
||||
use code_builder::CodeBuilder;
|
||||
use code_builder::HasCodeRepr;
|
||||
use shapely::derive_clone_plus;
|
||||
use enso_shapely::derive_clone_plus;
|
||||
|
||||
|
||||
|
||||
|
@ -14,10 +14,10 @@ ensogl-core-msdf-sys = { version = "0.1.0" , path = "../ensogl/msdf-sys"
|
||||
ensogl-system-web = { version = "0.1.0" , path = "../lib/system/web" }
|
||||
data = { version = "0.1.0" , path = "../lib/data" }
|
||||
enso-frp = { version = "0.1.0" , path = "../lib/frp" }
|
||||
enso-prelude = { version = "0.1.0" , path = "../lib/prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
graph-editor = { version = "0.1.0" , path = "../lib/graph-editor" }
|
||||
logger = { version = "0.1.0" , path = "../lib/logger" }
|
||||
shapely = { version = "0.1.0" , path = "../lib/shapely/impl" }
|
||||
enso-shapely = { version = "0.1.0" }
|
||||
|
||||
ast = { version = "0.1.0" , path = "ast/impl" }
|
||||
enso-protocol = { version = "0.1.0" , path = "enso-protocol" }
|
||||
|
@ -19,6 +19,6 @@ uuid = { version = "0.8.1", features = ["serde","v4","wasm-bindgen"] }
|
||||
|
||||
ast-macros = { version = "0.1.0", path = "../macros" }
|
||||
data = { version = "0.1.0", path = "../../../lib/data" }
|
||||
enso-prelude = { version = "0.1.0", path = "../../../lib/prelude" }
|
||||
shapely = { version = "0.1.0", path = "../../../lib/shapely/impl" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
enso-shapely = { version = "0.1.0" }
|
||||
utils = { version = "0.1.0", path = "../../utils" }
|
||||
|
@ -13,5 +13,5 @@ pub fn iterate_subtree<T>(ast:T) -> impl Iterator<Item=T::Item>
|
||||
}
|
||||
};
|
||||
|
||||
shapely::GeneratingIterator(generator)
|
||||
enso_shapely::GeneratingIterator(generator)
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ use serde::Deserialize;
|
||||
use serde::ser::Serializer;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::Serialize;
|
||||
use shapely::*;
|
||||
use enso_shapely::*;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// A sequence of AST nodes, typically the "token soup".
|
||||
|
@ -15,8 +15,8 @@ proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
Inflector = "0.11.4"
|
||||
|
||||
macro-utils = { version = "0.1.0" , path = "../../../lib/macro-utils" }
|
||||
enso-prelude = { version = "0.1.0" , path = "../../../lib/prelude" }
|
||||
enso-macro-utils = { version = "0.1.0" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
|
||||
[dependencies.syn]
|
||||
version = "1.0"
|
||||
|
@ -10,8 +10,8 @@ use crate::prelude::*;
|
||||
use crate::token::TokenDescription;
|
||||
|
||||
use enso_prelude as prelude;
|
||||
use macro_utils::gather_all_type_reprs;
|
||||
use macro_utils::repr;
|
||||
use enso_macro_utils::gather_all_type_reprs;
|
||||
use enso_macro_utils::repr;
|
||||
use proc_macro2::TokenStream;
|
||||
use proc_macro2::Ident;
|
||||
use proc_macro2::Span;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use macro_utils::path_segment_generic_args;
|
||||
use enso_macro_utils::path_segment_generic_args;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::Expr;
|
||||
|
@ -10,8 +10,8 @@ crate-type = ["cdylib", "rlib"]
|
||||
[dependencies]
|
||||
data = { version = "0.1.0" , path = "../../lib/data" }
|
||||
json-rpc = { version = "0.1.0" , path = "../json-rpc" }
|
||||
enso-prelude = { version = "0.1.0" , path = "../../lib/prelude" }
|
||||
shapely = { version = "0.1.0" , path = "../../lib/shapely/impl" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
enso-shapely = { version = "0.1.0" }
|
||||
logger = { version = "0.1.0" , path = "../../lib/logger" }
|
||||
utils = { version = "0.1.0" , path = "../utils" }
|
||||
|
||||
|
@ -8,13 +8,13 @@ edition = "2018"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
enso-prelude = { version = "0.1.0" , path = "../../lib/prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
ensogl-system-web = { version = "0.1.0" , path = "../../lib/system/web" }
|
||||
|
||||
futures = { version = "0.3.1" }
|
||||
failure = { version = "0.1.6" }
|
||||
serde = { version = "1.0.0" , features = ["derive"] }
|
||||
serde_json = { version = "1.0.0" }
|
||||
shapely = { version = "0.1.0" , path = "../../lib/shapely/impl" }
|
||||
enso-shapely = { version = "0.1.0" }
|
||||
shrinkwraprs = { version = "0.3.0" }
|
||||
utils = { version = "0.1.0" , path = "../utils" }
|
||||
|
@ -132,7 +132,7 @@ pub type OngoingCalls = HashMap<Id,oneshot::Sender<ReplyMessage>>;
|
||||
/// `DeserializeOwned` and deserialize from JSON maps with `method` and `params`
|
||||
/// fields.
|
||||
|
||||
pub use shapely::shared;
|
||||
pub use enso_shapely::shared;
|
||||
|
||||
shared! { Handler
|
||||
|
||||
|
@ -11,7 +11,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
[dependencies]
|
||||
ast = { version = "0.1.0", path = "../ast/impl" }
|
||||
data = { version = "0.1.0", path = "../../lib/data" }
|
||||
enso-prelude = { version = "0.1.0", path = "../../lib/prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
utils = { version = "0.1.0", path = "../utils" }
|
||||
|
||||
console_error_panic_hook = { version = "0.1.6" }
|
||||
|
@ -7,7 +7,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
ast = { version = "0.1.0", path = "../ast/impl" }
|
||||
data = { version = "0.1.0", path = "../../lib/data" }
|
||||
enso-prelude = { version = "0.1.0", path = "../../lib/prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
utils = { version = "0.1.0", path = "../utils" }
|
||||
|
||||
failure = { version = "0.1.6" }
|
||||
|
@ -43,6 +43,7 @@ pub mod prelude {
|
||||
pub use utils::fail::FallibleResult;
|
||||
}
|
||||
|
||||
use traits::*;
|
||||
use prelude::*;
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@ use ensogl::system::web;
|
||||
use enso_frp::io::keyboard::Keyboard;
|
||||
use enso_frp::io::keyboard;
|
||||
use nalgebra::Vector2;
|
||||
use shapely::shared;
|
||||
use enso_shapely::shared;
|
||||
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@ edition = "2018"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
enso-prelude = { version = "0.1.0" , path = "../../lib/prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
|
||||
failure = "0.1.5"
|
||||
futures = "0.3.1"
|
||||
|
@ -7,4 +7,4 @@ edition = "2018"
|
||||
[lib]
|
||||
|
||||
[dependencies]
|
||||
enso-prelude = { version = "0.1.0" , path = "../prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
|
@ -9,4 +9,4 @@ edition = "2018"
|
||||
[features]
|
||||
|
||||
[dependencies]
|
||||
enso-prelude = { version = "0.1.0", path = "../prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
|
@ -8,6 +8,6 @@ edition = "2018"
|
||||
crate-type = ["rlib", "cdylib"]
|
||||
|
||||
[dependencies]
|
||||
enso-prelude = { version = "0.1.0" , path = "../prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
|
||||
serde = { version = "1.0" , features = ["derive"] }
|
||||
|
@ -8,7 +8,7 @@ edition = "2018"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
shapely = { version = "0.1.0" , path = "../shapely/impl" }
|
||||
enso-shapely = { version = "0.1.0" }
|
||||
ensogl = { version = "0.1.0" , path = "../../ensogl" }
|
||||
ensogl-core-msdf-sys = { version = "0.1.0" , path = "../../ensogl/msdf-sys" }
|
||||
ensogl-system-web = { version = "0.1.0" , path = "../system/web" }
|
||||
@ -18,7 +18,7 @@ ide = { version = "0.1.0" , path = "../../ide" }
|
||||
span-tree = { version = "0.1.0" , path = "../../ide/span-tree" }
|
||||
ast = { version = "0.1.0" , path = "../../ide/ast/impl" }
|
||||
|
||||
enso-prelude = { version = "0.1.0" , path = "../prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
|
||||
js-sys = { version = "0.3.28" }
|
||||
nalgebra = { version = "0.21.1" }
|
||||
|
@ -9,7 +9,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
enso-callback = { version = "0.1.0" , path = "../callback" }
|
||||
enso-generics = { version = "0.1.0" , path = "../generics" }
|
||||
enso-prelude = { version = "0.1.0" , path = "../prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
ensogl-system-web = { version = "0.1.0" , path = "../system/web" }
|
||||
keyboard-types = { version = "0.5.0" }
|
||||
nalgebra = { version = "0.21.1" }
|
||||
|
@ -7,9 +7,9 @@ edition = "2018"
|
||||
[dependencies]
|
||||
ast = { version = "0.1.0" , path = "../../ide/ast/impl" }
|
||||
span-tree = { version = "0.1.0" , path = "../../ide/span-tree" }
|
||||
shapely = { version = "0.1.0" , path = "../shapely/impl" }
|
||||
enso-shapely = { version = "0.1.0" }
|
||||
ensogl = { version = "0.1.0" , path = "../../ensogl" }
|
||||
enso-prelude = { version = "0.1.0" , path = "../prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
logger = { version = "0.1.0" , path = "../logger" }
|
||||
enso-frp = { version = "0.1.0" , path = "../frp" }
|
||||
|
||||
|
@ -10,8 +10,8 @@ edition = "2018"
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
enso-prelude = { version = "0.1.0", path = "../prelude" }
|
||||
shapely = { version = "0.1.0", path = "../shapely/impl" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
enso-shapely = { version = "0.1.0" }
|
||||
wasm-bindgen = { version = "=0.2.58", features = ["nightly"] }
|
||||
|
||||
[dependencies.web-sys]
|
||||
|
@ -6,7 +6,7 @@ use crate::Message;
|
||||
use crate::AnyLogger;
|
||||
use crate::enabled;
|
||||
|
||||
use shapely::CloneRef;
|
||||
use enso_shapely::CloneRef;
|
||||
use std::fmt::Debug;
|
||||
|
||||
|
||||
|
@ -5,7 +5,7 @@ use enso_prelude::*;
|
||||
use crate::AnyLogger;
|
||||
use crate::Message;
|
||||
|
||||
use shapely::CloneRef;
|
||||
use enso_shapely::CloneRef;
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
|
@ -1,17 +0,0 @@
|
||||
[package]
|
||||
name = "macro-utils"
|
||||
version = "0.1.0"
|
||||
authors = ["Enso Team <contact@luna-lang.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
|
||||
[dependencies.syn]
|
||||
version = "1.0"
|
||||
features = [
|
||||
'extra-traits',
|
||||
'full', # for syn::ItemStruct
|
||||
'visit'
|
||||
]
|
@ -1,358 +0,0 @@
|
||||
//! A number of helper functions meant to be used in the procedural macros
|
||||
//! definitions.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![feature(trait_alias)]
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use proc_macro2::TokenTree;
|
||||
use quote::quote;
|
||||
use std::iter::FromIterator;
|
||||
use syn::visit::Visit;
|
||||
use syn::WhereClause;
|
||||
use syn::WherePredicate;
|
||||
use syn;
|
||||
|
||||
|
||||
|
||||
// =====================
|
||||
// === Trait Aliases ===
|
||||
// =====================
|
||||
|
||||
pub trait Str = Into<String> + AsRef<str>;
|
||||
|
||||
|
||||
|
||||
// ==========================
|
||||
// === Token Stream Utils ===
|
||||
// ==========================
|
||||
|
||||
/// Maps all the tokens in the stream using a given function.
|
||||
pub fn map_tokens<F:Fn(TokenTree) -> TokenTree>
|
||||
(input:TokenStream, f:F) -> TokenStream {
|
||||
let ret_iter = input.into_iter().map(f);
|
||||
TokenStream::from_iter(ret_iter)
|
||||
}
|
||||
|
||||
/// Rewrites stream replacing each token with a sequence of tokens returned by
|
||||
/// the given function. The groups (e.g. token tree within braces) are unpacked,
|
||||
/// rewritten and repacked into groups -- the function is applied recursively.
|
||||
pub fn rewrite_stream
|
||||
<F:Fn(TokenTree) -> TokenStream + Copy>
|
||||
(input:TokenStream, f:F) -> TokenStream {
|
||||
let mut ret = TokenStream::new();
|
||||
for token in input.into_iter() {
|
||||
match token {
|
||||
proc_macro2::TokenTree::Group(group) => {
|
||||
let delim = group.delimiter();
|
||||
let span = group.span();
|
||||
let rewritten = rewrite_stream(group.stream(), f);
|
||||
let mut new_group = proc_macro2::Group::new(delim,rewritten);
|
||||
new_group.set_span(span);
|
||||
let new_group = vec![TokenTree::from(new_group)];
|
||||
ret.extend(new_group.into_iter())
|
||||
}
|
||||
_ => ret.extend(f(token)),
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===================
|
||||
// === Token Utils ===
|
||||
// ===================
|
||||
|
||||
/// Is the given token an identifier matching to a given string?
|
||||
pub fn matching_ident(token:&TokenTree, name:&str) -> bool {
|
||||
match token {
|
||||
TokenTree::Ident(ident) => *ident == name,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ============
|
||||
// === Repr ===
|
||||
// ============
|
||||
|
||||
/// Obtains text representation of given `ToTokens`-compatible input.
|
||||
pub fn repr<T: quote::ToTokens>(t:&T) -> String {
|
||||
quote!(#t).to_string()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===================
|
||||
// === Field Utils ===
|
||||
// ===================
|
||||
|
||||
/// Collects all fields, named or not.
|
||||
pub 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::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns token that refers to the field.
|
||||
///
|
||||
/// It is the field name for named field and field index for unnamed fields.
|
||||
pub fn field_ident_token(field:&syn::Field, index:syn::Index) -> TokenStream {
|
||||
match &field.ident {
|
||||
Some(ident) => quote!(#ident),
|
||||
None => quote!(#index),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns names of the named fields.
|
||||
pub fn field_names(fields:&syn::FieldsNamed) -> Vec<&syn::Ident> {
|
||||
fields.named.iter().map(|field| {
|
||||
field.ident.as_ref().expect("Impossible: no name on a named field.")
|
||||
}).collect()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ==================
|
||||
// === Path Utils ===
|
||||
// ==================
|
||||
|
||||
/// Checks if a given `Path` consists of a single identifier same as given string.
|
||||
pub fn path_matching_ident(path:&syn::Path, str:impl Str) -> bool {
|
||||
path.get_ident().map_or(false, |ident| ident == str.as_ref())
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ======================
|
||||
// === Index Sequence ===
|
||||
// ======================
|
||||
|
||||
/// For given length, returns a sequence of Literals like `[0,1,2…]`. These are unsuffixed
|
||||
/// usize literals, so e.g. can be used to identify the tuple unnamed fields.
|
||||
pub fn index_sequence(len:usize) -> Vec<syn::Index> {
|
||||
(0..len).map(syn::Index::from).collect()
|
||||
}
|
||||
|
||||
/// For given length returns sequence of identifiers like `[field0,field1,…]`.
|
||||
pub fn identifier_sequence(len:usize) -> Vec<syn::Ident> {
|
||||
let format_field = |ix| quote::format_ident!("field{}",ix);
|
||||
(0..len).map(format_field).collect()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =======================
|
||||
// === Type Path Utils ===
|
||||
// =======================
|
||||
|
||||
/// Obtain list of generic arguments on the path's segment.
|
||||
pub fn path_segment_generic_args
|
||||
(segment:&syn::PathSegment) -> Vec<&syn::GenericArgument> {
|
||||
match segment.arguments {
|
||||
syn::PathArguments::AngleBracketed(ref args) =>
|
||||
args.args.iter().collect(),
|
||||
_ =>
|
||||
Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain list of generic arguments on the path's last segment.
|
||||
///
|
||||
/// Empty, if path contains no segments.
|
||||
pub fn ty_path_generic_args
|
||||
(ty_path:&syn::TypePath) -> Vec<&syn::GenericArgument> {
|
||||
ty_path.path.segments.last().map_or(Vec::new(), path_segment_generic_args)
|
||||
}
|
||||
|
||||
/// Obtain list of type arguments on the path's last segment.
|
||||
pub fn ty_path_type_args
|
||||
(ty_path:&syn::TypePath) -> Vec<&syn::Type> {
|
||||
ty_path_generic_args(ty_path).iter().filter_map( |generic_arg| {
|
||||
match generic_arg {
|
||||
syn::GenericArgument::Type(t) => Some(t),
|
||||
_ => None,
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
|
||||
/// Last type argument of the last segment on the type path.
|
||||
pub fn last_type_arg(ty_path:&syn::TypePath) -> Option<&syn::GenericArgument> {
|
||||
ty_path_generic_args(ty_path).last().copied()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =====================
|
||||
// === Collect Types ===
|
||||
// =====================
|
||||
|
||||
/// Visitor that accumulates all visited `syn::TypePath`.
|
||||
#[derive(Default)]
|
||||
pub struct TypeGatherer<'ast> {
|
||||
/// Observed types accumulator.
|
||||
pub types: Vec<&'ast syn::TypePath>
|
||||
}
|
||||
|
||||
impl<'ast> Visit<'ast> for TypeGatherer<'ast> {
|
||||
fn visit_type_path(&mut self, node:&'ast syn::TypePath) {
|
||||
self.types.push(node);
|
||||
syn::visit::visit_type_path(self, node);
|
||||
}
|
||||
}
|
||||
|
||||
/// All `TypePath`s in the given's `Type` subtree.
|
||||
pub fn gather_all_types(node:&syn::Type) -> Vec<&syn::TypePath> {
|
||||
let mut type_gather = TypeGatherer::default();
|
||||
type_gather.visit_type(node);
|
||||
type_gather.types
|
||||
}
|
||||
|
||||
/// All text representations of `TypePath`s in the given's `Type` subtree.
|
||||
pub fn gather_all_type_reprs(node:&syn::Type) -> Vec<String> {
|
||||
gather_all_types(node).iter().map(|t| repr(t)).collect()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =======================
|
||||
// === Type Dependency ===
|
||||
// =======================
|
||||
|
||||
/// Naive type equality test by comparing its representation with a string.
|
||||
pub fn type_matches_repr(ty:&syn::Type, target_repr:&str) -> bool {
|
||||
repr(ty) == target_repr
|
||||
}
|
||||
|
||||
/// Naive type equality test by comparing their text representations.
|
||||
pub fn type_matches(ty:&syn::Type, target_param:&syn::GenericParam) -> bool {
|
||||
type_matches_repr(ty, &repr(target_param))
|
||||
}
|
||||
|
||||
/// Does type depends on the given type parameter.
|
||||
pub fn type_depends_on(ty:&syn::Type, target_param:&syn::GenericParam) -> bool {
|
||||
let target_param = repr(target_param);
|
||||
let relevant_types = gather_all_types(ty);
|
||||
relevant_types.iter().any(|ty| repr(ty) == target_param)
|
||||
}
|
||||
|
||||
/// Does enum variant depend on the given type parameter.
|
||||
pub fn variant_depends_on
|
||||
(var:&syn::Variant, target_param:&syn::GenericParam) -> bool {
|
||||
var.fields.iter().any(|field| type_depends_on(&field.ty, target_param))
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===================
|
||||
// === WhereClause ===
|
||||
// ===================
|
||||
|
||||
/// Creates a new where clause from provided sequence of where predicates.
|
||||
pub fn new_where_clause(predicates:impl IntoIterator<Item=WherePredicate>) -> WhereClause {
|
||||
let predicates = syn::punctuated::Punctuated::from_iter(predicates);
|
||||
WhereClause {where_token:Default::default(),predicates}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =============
|
||||
// === Tests ===
|
||||
// =============
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
fn parse<T:syn::parse::Parse>(code:&str) -> T {
|
||||
syn::parse_str(code).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repr_round_trips() {
|
||||
let program = "pub fn repr<T: quote::ToTokens>(t: &T) -> String {}";
|
||||
let tokens = parse::<TokenStream>(program);
|
||||
let quoted_program = repr(&tokens);
|
||||
let tokens2 = parse::<TokenStream>("ed_program);
|
||||
// check only second round-trip, first is allowed to break whitespace
|
||||
assert_eq!(repr(&tokens), repr(&tokens2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fields_list_test() {
|
||||
let tuple_like = "struct Unnamed(i32, String, T);";
|
||||
let proper_struct = "struct Named{i: i32, s: String, t: T}";
|
||||
let expected_types = vec!["i32", "String", "T"];
|
||||
|
||||
fn assert_field_types(program:&str, expected_types:&[&str]) {
|
||||
let tokens = parse::<syn::ItemStruct>(program);
|
||||
let fields = fields_list(&tokens.fields);
|
||||
let types = fields.iter().map(|f| repr(&f.ty));
|
||||
assert_eq!(Vec::from_iter(types), expected_types);
|
||||
}
|
||||
|
||||
assert_field_types(tuple_like, &expected_types);
|
||||
assert_field_types(proper_struct, &expected_types);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_dependency() {
|
||||
let param:syn::GenericParam = parse("T");
|
||||
let depends = |code| {
|
||||
let ty:syn::Type = parse(code);
|
||||
type_depends_on(&ty, ¶m)
|
||||
};
|
||||
|
||||
// sample types that depend on `T`
|
||||
let dependents = vec!{
|
||||
"T",
|
||||
"Option<T>",
|
||||
"Pair<T, U>",
|
||||
"Pair<U, T>",
|
||||
"Pair<U, (T,)>",
|
||||
"&T",
|
||||
"&'t mut T",
|
||||
};
|
||||
// sample types that do not depend on `T`
|
||||
let independents = vec!{
|
||||
"Tt",
|
||||
"Option<Tt>",
|
||||
"Pair<Tt, U>",
|
||||
"Pair<U, Tt>",
|
||||
"Pair<U, Tt>",
|
||||
"i32",
|
||||
"&str",
|
||||
};
|
||||
for dependent in dependents {
|
||||
assert!(depends(dependent), "{} must depend on {}"
|
||||
, repr(&dependent), repr(¶m));
|
||||
}
|
||||
for independent in independents {
|
||||
assert!(!depends(independent), "{} must not depend on {}"
|
||||
, repr(&independent), repr(¶m));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collecting_type_path_args() {
|
||||
fn check(expected_type_args:Vec<&str>, ty_path:&str) {
|
||||
let ty_path = parse(ty_path);
|
||||
let args = super::ty_path_type_args(&ty_path);
|
||||
assert_eq!(expected_type_args.len(), args.len());
|
||||
let zipped = expected_type_args.iter().zip(args.iter());
|
||||
for (expected,got) in zipped {
|
||||
assert_eq!(expected, &repr(got));
|
||||
}
|
||||
}
|
||||
check(vec!["T"] , "std::Option<T>");
|
||||
check(vec!["U"] , "std::Option<U>");
|
||||
check(vec!["A", "B"], "Either<A,B>");
|
||||
assert_eq!(super::last_type_arg(&parse("i32")), None);
|
||||
assert_eq!(repr(&super::last_type_arg(&parse("Foo<C>"))), "C");
|
||||
}
|
||||
}
|
@ -9,4 +9,4 @@ edition = "2018"
|
||||
[features]
|
||||
|
||||
[dependencies]
|
||||
enso-prelude = { version = "0.1.0", path = "../prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
|
@ -1,68 +0,0 @@
|
||||
[package]
|
||||
name = "enso-prelude"
|
||||
version = "0.1.0"
|
||||
authors = ["Enso Team <contact@luna-lang.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
|
||||
[dependencies]
|
||||
shapely = { version = "0.1.0" , path = "../shapely/impl" }
|
||||
|
||||
boolinator = "2.4.0"
|
||||
derivative = "1.0.3"
|
||||
derive_more = "0.99.2"
|
||||
enclose = "1.1.8"
|
||||
failure = "0.1.5"
|
||||
ifmt = "0.2.0"
|
||||
itertools = "0.8"
|
||||
lazy_static = "1.4"
|
||||
num = "0.2.0"
|
||||
paste = "0.1"
|
||||
shrinkwraprs = "0.3.0"
|
||||
smallvec = "1.0.0"
|
||||
weak-table = "0.2.3"
|
||||
wasm-bindgen = { version = "=0.2.58" , features = ["nightly"] }
|
||||
|
||||
# TODO: should be behind a flag, as the `nalgebra` package is pretty big and this crate would be
|
||||
# also useful for projects which do not require `nalgebra`.
|
||||
nalgebra = "0.21.1"
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3.4"
|
||||
features = [
|
||||
'CanvasRenderingContext2d',
|
||||
'CssStyleDeclaration',
|
||||
'Document',
|
||||
'Element',
|
||||
'EventTarget',
|
||||
'KeyboardEvent',
|
||||
'HtmlCanvasElement',
|
||||
'HtmlCollection',
|
||||
'HtmlDivElement',
|
||||
'HtmlElement',
|
||||
'HtmlImageElement',
|
||||
'Location',
|
||||
'Node',
|
||||
'Url',
|
||||
'WebGlBuffer',
|
||||
'WebGlFramebuffer',
|
||||
'WebGlProgram',
|
||||
'WebGlRenderingContext',
|
||||
'WebGlShader',
|
||||
'WebGlSync',
|
||||
'WebGlTexture',
|
||||
'WebGl2RenderingContext',
|
||||
'WebGlUniformLocation',
|
||||
'WebGlUniformLocation',
|
||||
'WebGlVertexArrayObject',
|
||||
'Window',
|
||||
'console',
|
||||
'EventTarget',
|
||||
'Event',
|
||||
'MouseEvent',
|
||||
'Performance',
|
||||
'WheelEvent',
|
||||
'DomRect',
|
||||
'AddEventListenerOptions'
|
||||
]
|
@ -1,56 +0,0 @@
|
||||
|
||||
use crate::*;
|
||||
pub use shapely::CloneRef;
|
||||
|
||||
|
||||
|
||||
// ================
|
||||
// === CloneRef ===
|
||||
// ================
|
||||
|
||||
/// Clone for internal-mutable structures. This trait can be implemented only if mutating one
|
||||
/// structure will be reflected in all of its clones. Please note that it does not mean that all the
|
||||
/// fields needs to provide internal mutability as well. For example, a structure can remember it's
|
||||
/// creation time and store it as `f32`. As long as it cannot be mutated, the structure can
|
||||
/// implement `CloneRef`. In order to guide the auto-deriving mechanism, it is advised to wrap all
|
||||
/// immutable fields in the `Immutable` newtype.
|
||||
pub trait CloneRef: Sized {
|
||||
fn clone_ref(&self) -> Self;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_clone_ref_as_clone {
|
||||
([$($bounds:tt)*] $($toks:tt)*) => {
|
||||
impl <$($bounds)*> CloneRef for $($toks)* {
|
||||
fn clone_ref(&self) -> Self {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($($toks:tt)*) => {
|
||||
impl CloneRef for $($toks)* {
|
||||
fn clone_ref(&self) -> Self {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_clone_ref_as_clone!(());
|
||||
impl_clone_ref_as_clone!(f32);
|
||||
impl_clone_ref_as_clone!(f64);
|
||||
impl_clone_ref_as_clone!(i32);
|
||||
impl_clone_ref_as_clone!(i64);
|
||||
impl_clone_ref_as_clone!(usize);
|
||||
impl_clone_ref_as_clone!([T] PhantomData<T>);
|
||||
impl_clone_ref_as_clone!([T:?Sized] Rc<T>);
|
||||
impl_clone_ref_as_clone!([T:?Sized] Weak<T>);
|
||||
|
||||
impl_clone_ref_as_clone!(wasm_bindgen::JsValue);
|
||||
impl_clone_ref_as_clone!(web_sys::HtmlDivElement);
|
||||
impl_clone_ref_as_clone!(web_sys::HtmlElement);
|
||||
impl_clone_ref_as_clone!(web_sys::Performance);
|
||||
impl_clone_ref_as_clone!(web_sys::WebGl2RenderingContext);
|
||||
impl_clone_ref_as_clone!(web_sys::HtmlCanvasElement);
|
||||
impl_clone_ref_as_clone!(web_sys::EventTarget);
|
@ -1,6 +0,0 @@
|
||||
//! This module exports collections which are popular enough to be available everywhere.
|
||||
|
||||
pub use smallvec::SmallVec;
|
||||
pub use std::collections::BTreeMap;
|
||||
pub use std::collections::HashMap;
|
||||
pub use std::collections::HashSet;
|
@ -1,9 +0,0 @@
|
||||
//! Generic data types and utilities.
|
||||
|
||||
pub mod at_least_one_of_two;
|
||||
pub mod monoid;
|
||||
pub mod semigroup;
|
||||
|
||||
pub use at_least_one_of_two::*;
|
||||
pub use monoid::*;
|
||||
pub use semigroup::*;
|
@ -1,55 +0,0 @@
|
||||
//! Definition of `AtLeastOneOfTwo`.
|
||||
|
||||
|
||||
|
||||
// =======================
|
||||
// === AtLeastOneOfTwo ===
|
||||
// =======================
|
||||
|
||||
/// A struct similar to `Option` and `Either`. It can contain the first value, or the second value,
|
||||
/// or both of them at the same time.
|
||||
#[derive(Debug,Clone,Copy)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum AtLeastOneOfTwo<T1,T2> {
|
||||
First(T1),
|
||||
Second(T2),
|
||||
Both(T1,T2)
|
||||
}
|
||||
|
||||
impl<T:PartialEq> AtLeastOneOfTwo<T,T> {
|
||||
/// Checks whether the values are equal.
|
||||
pub fn same(&self) -> bool {
|
||||
match self {
|
||||
Self::Both(t1,t2) => t1 == t2,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1,T2> AtLeastOneOfTwo<T1,T2> {
|
||||
/// Extracts the first value if exists.
|
||||
pub fn first(&self) -> Option<&T1> {
|
||||
match self {
|
||||
Self::Both(t1,_) => Some(t1),
|
||||
Self::First(t1) => Some(t1),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the second value if exists.
|
||||
pub fn second(&self) -> Option<&T2> {
|
||||
match self {
|
||||
Self::Both(_,t2) => Some(t2),
|
||||
Self::Second(t2) => Some(t2),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts both of the value if exist.
|
||||
pub fn both(&self) -> Option<(&T1,&T2)> {
|
||||
match self {
|
||||
Self::Both(t1,t2) => Some((t1,t2)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
//! A class for monoids (types with an associative binary operation that has an identity) with
|
||||
//! various general-purpose instances.
|
||||
|
||||
use super::semigroup::Semigroup;
|
||||
|
||||
|
||||
|
||||
// ===============
|
||||
// === Monoid ====
|
||||
// ===============
|
||||
|
||||
/// Mutable Monoid definition.
|
||||
pub trait Monoid : Default + Semigroup {
|
||||
/// Repeat a value n times. Given that this works on a Monoid it will not fail if you request 0
|
||||
/// or fewer repetitions.
|
||||
fn times_mut(&mut self, n:usize) {
|
||||
if n == 0 {
|
||||
*self = Default::default()
|
||||
} else {
|
||||
let val = self.clone();
|
||||
for _ in 0..n-1 {
|
||||
self.concat_mut(&val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn times(&self, n:usize) -> Self {
|
||||
std::iter::repeat(self).take(n).fold(Default::default(),|l,r| l.concat_ref(r))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === Default Impls ===
|
||||
|
||||
impl<T> Monoid for T where T : Default + Semigroup {}
|
||||
|
||||
|
||||
|
||||
// =============
|
||||
// === Tests ===
|
||||
// =============
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn option() {
|
||||
let vec_nop : Vec<usize> = vec![];
|
||||
let vec_1_2 : Vec<usize> = vec![1,2];
|
||||
let vec_1_2_times_3 : Vec<usize> = vec![1,2,1,2,1,2];
|
||||
assert_eq!(vec_1_2.times(0) , vec_nop);
|
||||
assert_eq!(vec_1_2.times(1) , vec_1_2);
|
||||
assert_eq!(vec_1_2.times(3) , vec_1_2_times_3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: Think what to do with this. It would not be needed if tuples implement Iter. Alternatively
|
||||
// we could immplement own tuple type.
|
||||
|
||||
//trait Foldable {
|
||||
// type Item : Monoid;
|
||||
// fn fold(self) -> Self::Item;
|
||||
//}
|
||||
//
|
||||
//
|
||||
//
|
||||
//macro_rules! replace {
|
||||
// ($a:tt,$b:tt) => {$b};
|
||||
//}
|
||||
//
|
||||
//
|
||||
//macro_rules! define_foldable_for_tuple {
|
||||
// (0$(,$num:tt)*) => {
|
||||
// impl<T:Monoid> Foldable for (T,$(replace!{$num,T}),*) {
|
||||
// type Item = T;
|
||||
// fn fold(self) -> Self::Item {
|
||||
// self.0$(.concat(self.$num))*
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl<T:Monoid> Foldable for &(T,$(replace!{$num,T}),*) {
|
||||
// type Item = T;
|
||||
// fn fold(self) -> Self::Item {
|
||||
// self.0.clone()$(.concat(&self.$num))*
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
//}
|
||||
//
|
||||
//define_foldable_for_tuple![0];
|
||||
//define_foldable_for_tuple![0,1];
|
||||
//define_foldable_for_tuple![0,1,2];
|
||||
//define_foldable_for_tuple![0,1,2,3];
|
||||
//define_foldable_for_tuple![0,1,2,3,4];
|
||||
//define_foldable_for_tuple![0,1,2,3,4,5];
|
||||
//define_foldable_for_tuple![0,1,2,3,4,5,6];
|
||||
//define_foldable_for_tuple![0,1,2,3,4,5,6,7];
|
||||
//define_foldable_for_tuple![0,1,2,3,4,5,6,7,8];
|
||||
//define_foldable_for_tuple![0,1,2,3,4,5,6,7,8,9];
|
||||
//define_foldable_for_tuple![0,1,2,3,4,5,6,7,8,9,10];
|
||||
//define_foldable_for_tuple![0,1,2,3,4,5,6,7,8,9,10,11];
|
||||
//define_foldable_for_tuple![0,1,2,3,4,5,6,7,8,9,10,11,12];
|
||||
//define_foldable_for_tuple![0,1,2,3,4,5,6,7,8,9,10,11,12,13];
|
||||
//define_foldable_for_tuple![0,1,2,3,4,5,6,7,8,9,10,11,12,13,14];
|
||||
//define_foldable_for_tuple![0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
|
@ -1,143 +0,0 @@
|
||||
//! In mathematics, a semigroup is an algebraic structure consisting of a set together with an
|
||||
//! associative binary operation. A semigroup generalizes a monoid in that there might not exist an
|
||||
//! identity element. It also (originally) generalized a group (a monoid with all inverses) to a
|
||||
//! type where every element did not have to have an inverse, thus the name semigroup.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasher;
|
||||
use std::hash::Hash;
|
||||
use std::iter::Extend;
|
||||
|
||||
|
||||
|
||||
// =================
|
||||
// === Semigroup ===
|
||||
// =================
|
||||
|
||||
/// Mutable Semigroup definition. Impls should satisfy the associativity law:
|
||||
/// `x.concat(y.concat(z)) = x.concat(y).concat(z)`, in symbolic form:
|
||||
/// `x <> (y <> z) = (x <> y) <> z`
|
||||
pub trait PartialSemigroup<T> : Clone {
|
||||
/// An associative operation.
|
||||
fn concat_mut(&mut self, other:T);
|
||||
|
||||
/// An associative operation.
|
||||
fn concat_ref(&self, other:T) -> Self where Self:Clone {
|
||||
self.clone().concat(other)
|
||||
}
|
||||
|
||||
/// An associative operation.
|
||||
fn concat(mut self, other:T) -> Self {
|
||||
self.concat_mut(other);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Semigroup for T where T : PartialSemigroup<T> + for<'t> PartialSemigroup<&'t T> {}
|
||||
pub trait Semigroup : PartialSemigroup<Self> + for<'t> PartialSemigroup<&'t Self> {
|
||||
fn partial_times_mut(&mut self, n:usize) {
|
||||
let val = self.clone();
|
||||
for _ in 0..n-1 {
|
||||
self.concat_mut(&val)
|
||||
}
|
||||
}
|
||||
|
||||
fn partial_times(mut self, n:usize) -> Self {
|
||||
self.partial_times_mut(n);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ====================
|
||||
// === Stdlib Impls ===
|
||||
// ====================
|
||||
|
||||
// === Option ===
|
||||
|
||||
impl<T:Semigroup> PartialSemigroup<&Option<T>> for Option<T> {
|
||||
fn concat_mut(&mut self, other:&Self) {
|
||||
if let Some(r) = other {
|
||||
match self {
|
||||
None => *self = Some(r.clone()),
|
||||
Some(l) => l.concat_mut(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Semigroup> PartialSemigroup<Option<T>> for Option<T> {
|
||||
fn concat_mut(&mut self, other:Self) {
|
||||
if let Some(r) = other {
|
||||
match self {
|
||||
None => *self = Some(r),
|
||||
Some(l) => l.concat_mut(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === HashMap ===
|
||||
|
||||
impl<K,V,S> PartialSemigroup<&HashMap<K,V,S>> for HashMap<K,V,S>
|
||||
where K : Eq + Hash + Clone,
|
||||
V : Semigroup,
|
||||
S : Clone + BuildHasher {
|
||||
fn concat_mut(&mut self, other:&Self) {
|
||||
for (key,new_val) in other {
|
||||
let key = key.clone();
|
||||
self.entry(key)
|
||||
.and_modify(|val| val.concat_mut(new_val))
|
||||
.or_insert_with(|| new_val.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K,V,S> PartialSemigroup<HashMap<K,V,S>> for HashMap<K,V,S>
|
||||
where K : Eq + Hash + Clone,
|
||||
V : Semigroup,
|
||||
S : Clone + BuildHasher {
|
||||
fn concat_mut(&mut self, other:Self) {
|
||||
for (key,new_val) in other {
|
||||
self.entry(key)
|
||||
.and_modify(|val| val.concat_mut(&new_val))
|
||||
.or_insert(new_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === Vec ===
|
||||
|
||||
impl<T:Clone> PartialSemigroup<&Vec<T>> for Vec<T> {
|
||||
fn concat_mut(&mut self, other:&Self) {
|
||||
self.extend(other.iter().cloned())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Clone> PartialSemigroup<Vec<T>> for Vec<T> {
|
||||
fn concat_mut(&mut self, other:Self) {
|
||||
self.extend(other.into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =============
|
||||
// === Tests ===
|
||||
// =============
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn option() {
|
||||
assert_eq!(None::<Vec<usize>>.concat(&None) , None);
|
||||
assert_eq!(Some(vec![1]).concat(&None) , Some(vec![1]));
|
||||
assert_eq!(None.concat(&Some(vec![1])) , Some(vec![1]));
|
||||
assert_eq!(Some(vec![1]).concat(&Some(vec![2])) , Some(vec![1,2]));
|
||||
}
|
||||
}
|
@ -1,326 +0,0 @@
|
||||
//! This module re-exports a lot of useful stuff. It is not meant to be used
|
||||
//! by libraries, but it is definitely usefull for bigger projects. It also
|
||||
//! defines several aliases and utils which may find their place in new
|
||||
//! libraries in the future.
|
||||
|
||||
#![warn(unsafe_code)]
|
||||
#![warn(missing_copy_implementations)]
|
||||
#![warn(missing_debug_implementations)]
|
||||
#![feature(specialization)]
|
||||
#![feature(trait_alias)]
|
||||
|
||||
mod clone;
|
||||
mod collections;
|
||||
mod data;
|
||||
mod macros;
|
||||
mod option;
|
||||
mod phantom;
|
||||
mod reference;
|
||||
mod std_reexports;
|
||||
mod string;
|
||||
mod tp;
|
||||
mod wrapper;
|
||||
|
||||
pub use clone::*;
|
||||
pub use collections::*;
|
||||
pub use data::*;
|
||||
pub use macros::*;
|
||||
pub use option::*;
|
||||
pub use phantom::*;
|
||||
pub use reference::*;
|
||||
pub use std_reexports::*;
|
||||
pub use string::*;
|
||||
pub use tp::*;
|
||||
pub use wrapper::*;
|
||||
|
||||
pub use boolinator::Boolinator;
|
||||
pub use derivative::Derivative;
|
||||
pub use derive_more::*;
|
||||
pub use enclose::enclose;
|
||||
pub use failure::Fail;
|
||||
pub use ifmt::*;
|
||||
pub use itertools::Itertools;
|
||||
pub use lazy_static::lazy_static;
|
||||
pub use num::Num;
|
||||
pub use paste;
|
||||
pub use shrinkwraprs::Shrinkwrap;
|
||||
pub use weak_table::traits::WeakElement;
|
||||
pub use weak_table::traits::WeakKey;
|
||||
pub use weak_table::WeakKeyHashMap;
|
||||
pub use weak_table::WeakValueHashMap;
|
||||
pub use weak_table;
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
|
||||
|
||||
// =================
|
||||
// === Immutable ===
|
||||
// =================
|
||||
|
||||
/// A zero-overhead newtype which provides immutable access to its content. Of course this does not
|
||||
/// apply to internal mutability of the wrapped data. A good use case of this structure is when you
|
||||
/// want to pass an ownership to a structure, allow access all its public fields, but do not allow
|
||||
/// their modification.
|
||||
#[derive(Clone,Copy,Default)]
|
||||
pub struct Immutable<T> {
|
||||
data : T
|
||||
}
|
||||
|
||||
/// Constructor of the `Immutable` struct.
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Immutable<T>(data:T) -> Immutable<T> {
|
||||
Immutable {data}
|
||||
}
|
||||
|
||||
impl<T:Debug> Debug for Immutable<T> {
|
||||
fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.data.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Display> Display for Immutable<T> {
|
||||
fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.data.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Clone> CloneRef for Immutable<T> {
|
||||
fn clone_ref(&self) -> Self {
|
||||
Self {data:self.data.clone()}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<T> for Immutable<T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::borrow::Borrow<T> for Immutable<T> {
|
||||
fn borrow(&self) -> &T {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Immutable<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ==============
|
||||
// === ToImpl ===
|
||||
// ==============
|
||||
|
||||
/// Provides method `to`, which is just like `into` but allows fo superfish syntax.
|
||||
pub trait ToImpl: Sized {
|
||||
fn to<P>(self) -> P where Self:Into<P> {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
impl<T> ToImpl for T {}
|
||||
|
||||
// TODO
|
||||
// This impl should be hidden behind a flag. Not everybody using prelude want to import nalgebra.
|
||||
impl <T,R,C,S> TypeDisplay for nalgebra::Matrix<T,R,C,S>
|
||||
where T:nalgebra::Scalar, R:nalgebra::DimName, C:nalgebra::DimName {
|
||||
fn type_display() -> String {
|
||||
let cols = <C as nalgebra::DimName>::dim();
|
||||
let rows = <R as nalgebra::DimName>::dim();
|
||||
let item = type_name::<T>();
|
||||
match cols {
|
||||
1 => format!("Vector{}<{}>" , rows, item),
|
||||
_ => format!("Matrix{}x{}<{}>" , rows, cols, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! clone_boxed {
|
||||
( $name:ident ) => { paste::item! {
|
||||
#[allow(missing_docs)]
|
||||
pub trait [<CloneBoxedFor $name>] {
|
||||
fn clone_boxed(&self) -> Box<dyn $name>;
|
||||
}
|
||||
|
||||
impl<T:Clone+$name+'static> [<CloneBoxedFor $name>] for T {
|
||||
fn clone_boxed(&self) -> Box<dyn $name> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Box<dyn $name> {
|
||||
fn clone(&self) -> Self {
|
||||
self.clone_boxed()
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
/// Alias for `for<'t> &'t Self : Into<T>`.
|
||||
pub trait RefInto<T> = where for<'t> &'t Self : Into<T>;
|
||||
|
||||
|
||||
|
||||
// =================
|
||||
// === CloneCell ===
|
||||
// =================
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CloneCell<T> {
|
||||
data : UnsafeCell<T>
|
||||
}
|
||||
|
||||
impl<T> CloneCell<T> {
|
||||
pub fn new(elem:T) -> CloneCell<T> {
|
||||
CloneCell { data:UnsafeCell::new(elem) }
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn get(&self) -> T where T:Clone {
|
||||
unsafe {(*self.data.get()).clone()}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn set(&self, elem:T) {
|
||||
unsafe { *self.data.get() = elem; }
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn take(&self) -> T where T:Default {
|
||||
let ptr:&mut T = unsafe { &mut *self.data.get() };
|
||||
std::mem::take(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Clone> Clone for CloneCell<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self::new(self.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Default> Default for CloneCell<T> {
|
||||
fn default() -> Self {
|
||||
Self::new(default())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================
|
||||
// === CloneCell ===
|
||||
// =================
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CloneRefCell<T> {
|
||||
data : UnsafeCell<T>
|
||||
}
|
||||
|
||||
impl<T> CloneRefCell<T> {
|
||||
pub fn new(elem:T) -> CloneRefCell<T> {
|
||||
CloneRefCell { data:UnsafeCell::new(elem) }
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn get(&self) -> T where T:CloneRef {
|
||||
unsafe {(*self.data.get()).clone_ref()}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn set(&self, elem:T) {
|
||||
unsafe { *self.data.get() = elem; }
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn take(&self) -> T where T:Default {
|
||||
let ptr:&mut T = unsafe { &mut *self.data.get() };
|
||||
std::mem::take(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:CloneRef> Clone for CloneRefCell<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self::new(self.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:CloneRef> CloneRef for CloneRefCell<T> {
|
||||
fn clone_ref(&self) -> Self {
|
||||
Self::new(self.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Default> Default for CloneRefCell<T> {
|
||||
fn default() -> Self {
|
||||
Self::new(default())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ================================
|
||||
// === RefCell<Option<T>> Utils ===
|
||||
// ================================
|
||||
|
||||
pub trait RefcellOptionOps<T> {
|
||||
fn clear(&self);
|
||||
fn set(&self, val:T);
|
||||
fn set_if_none(&self, val:T);
|
||||
}
|
||||
|
||||
impl<T> RefcellOptionOps<T> for RefCell<Option<T>> {
|
||||
fn clear(&self) {
|
||||
*self.borrow_mut() = None;
|
||||
}
|
||||
|
||||
fn set(&self, val:T) {
|
||||
*self.borrow_mut() = Some(val);
|
||||
}
|
||||
|
||||
fn set_if_none(&self, val:T) {
|
||||
let mut ptr = self.borrow_mut();
|
||||
if ptr.is_some() { panic!("The value was already set.") }
|
||||
*ptr = Some(val)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ================================
|
||||
// === Strong / Weak References ===
|
||||
// ================================
|
||||
|
||||
/// Abstraction for a strong reference like `Rc` or newtypes over it.
|
||||
pub trait StrongRef : CloneRef {
|
||||
/// Downgraded reference type.
|
||||
type WeakRef : WeakRef<StrongRef=Self>;
|
||||
/// Creates a new weak reference of this allocation.
|
||||
fn downgrade(&self) -> Self::WeakRef;
|
||||
}
|
||||
|
||||
/// Abstraction for a weak reference like `Weak` or newtypes over it.
|
||||
pub trait WeakRef : CloneRef {
|
||||
/// Upgraded reference type.
|
||||
type StrongRef : StrongRef<WeakRef=Self>;
|
||||
/// Attempts to upgrade the weak referenc to a strong one, delaying dropping of the inner value
|
||||
/// if successful.
|
||||
fn upgrade(&self) -> Option<Self::StrongRef>;
|
||||
}
|
||||
|
||||
impl<T:?Sized> StrongRef for Rc<T> {
|
||||
type WeakRef = Weak<T>;
|
||||
fn downgrade(&self) -> Self::WeakRef {
|
||||
Rc::downgrade(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:?Sized> WeakRef for Weak<T> {
|
||||
type StrongRef = Rc<T>;
|
||||
fn upgrade(&self) -> Option<Self::StrongRef> {
|
||||
Weak::upgrade(self)
|
||||
}
|
||||
}
|
@ -1,173 +0,0 @@
|
||||
//! This macro defines set of common macros which are useful across different projects.
|
||||
|
||||
|
||||
/// Allows for nicer definition of impls, similar to what Haskell or Scala does. Reduces the needed
|
||||
/// boilerplate. For example, the following usage:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// struct A { name:String };
|
||||
/// impls! { From<A> for String { |t| t.name.clone() } }
|
||||
/// ```
|
||||
///
|
||||
/// compiles to:
|
||||
/// ```
|
||||
/// struct A { name:String };
|
||||
/// impl From<A> for String {
|
||||
/// fn from(t:A) -> Self {
|
||||
/// t.name.clone()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This macro is meant to support many standard traits (like From) and should grow in the future.
|
||||
/// Currently supported ones are:
|
||||
/// * From<…>
|
||||
/// * From + &From<…>
|
||||
/// * Into + &Into<…>
|
||||
/// * PhantomFrom<…>
|
||||
#[macro_export]
|
||||
macro_rules! impls {
|
||||
($([$($impl_params:tt)*])? From<$ty:ty> for $target:ty $(where [$($bounds:tt)*])? {
|
||||
|$arg:tt| $($result:tt)*
|
||||
} ) => {
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
impl <$($($impl_params)*)?> From <$ty> for $target $(where $($bounds)*)? {
|
||||
fn from (arg:$ty) -> Self {
|
||||
(|$arg:$ty| $($result)*)(arg)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($([$($impl_params:tt)*])? From + &From <$ty:ty> for $target:ty $(where [$($bounds:tt)*])? {
|
||||
|$arg:tt| $($result:tt)*
|
||||
} ) => {
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
#[allow(clippy::identity_conversion)]
|
||||
impl <$($($impl_params)*)?> From <$ty> for $target $(where $($bounds)*)? {
|
||||
fn from (arg:$ty) -> Self {
|
||||
(|$arg:$ty| $($result)*)(arg)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
#[allow(clippy::identity_conversion)]
|
||||
impl <$($($impl_params)*)?> From <&$ty> for $target $(where $($bounds)*)? {
|
||||
fn from (arg:&$ty) -> Self {
|
||||
(|$arg:&$ty| $($result)*)(arg)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($([$($impl_params:tt)*])? Into + &Into <$ty:ty> for $target:ty $(where [$($bounds:tt)*])? {
|
||||
|$arg:tt| $($result:tt)*
|
||||
} ) => {
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
#[allow(clippy::identity_conversion)]
|
||||
impl <$($($impl_params)*)?> Into <$ty> for $target $(where $($bounds)*)? {
|
||||
fn into(self) -> $ty {
|
||||
(|$arg:Self| $($result)*)(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
#[allow(clippy::identity_conversion)]
|
||||
impl <$($($impl_params)*)?> Into <$ty> for &$target $(where $($bounds)*)? {
|
||||
fn into(self) -> $ty {
|
||||
(|$arg:Self| $($result)*)(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($([$($impl_params:tt)*])? PhantomFrom<$ty:ty> for $target:ty {
|
||||
$($result:tt)*
|
||||
} ) => {
|
||||
impl <$($($impl_params)*)?> From <PhantomData<$ty>> for $target {
|
||||
fn from (_:PhantomData<$ty>) -> Self {
|
||||
$($result)*
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! alias {
|
||||
($( $(#$meta:tt)* $name:ident = {$($tok:tt)*} )*) => {$(
|
||||
$(#$meta)*
|
||||
pub trait $name: $($tok)* {}
|
||||
impl<T:$($tok)*> $name for T {}
|
||||
)*};
|
||||
|
||||
(no_docs $( $(#$meta:tt)* $name:ident = {$($tok:tt)*} )*) => {$(
|
||||
$(#$meta)*
|
||||
#[allow(missing_docs)]
|
||||
pub trait $name: $($tok)* {}
|
||||
impl<T:$($tok)*> $name for T {}
|
||||
)*};
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ==============
|
||||
// === Lambda ===
|
||||
// ==============
|
||||
|
||||
/// Clones all arguments from the first argument list by using `CloneRef` and defines lambda with
|
||||
/// arguments from the second argument list (if present). For example, the following usage
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// f! { (a,b)(c) a + b + c }
|
||||
/// ```
|
||||
///
|
||||
/// is equivalent to:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// {
|
||||
/// let a = a.clone_ref();
|
||||
/// let b = b.clone_ref();
|
||||
/// move |c| { a + b + c }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! f {
|
||||
([$($name:ident),*] ($($args:tt)*) $($expr:tt)*) => {
|
||||
{
|
||||
$(let $name = $name.clone_ref();)*
|
||||
move |$($args)*| { $($expr)* }
|
||||
}
|
||||
};
|
||||
|
||||
([$($name:ident),*] $($expr:tt)*) => {
|
||||
{
|
||||
$(let $name = $name.clone_ref();)*
|
||||
move || { $($expr)* }
|
||||
}
|
||||
};
|
||||
|
||||
(($($args:tt)*) $name:ident . $($toks:tt)*) => {
|
||||
f! { [$name] ($($args)*) $name . $($toks)* }
|
||||
};
|
||||
|
||||
(($($args:tt)*) { $name:ident . $($toks:tt)* }) => {
|
||||
f! { [$name] ($($args)*) { $name . $($toks)* } }
|
||||
};
|
||||
|
||||
($name:ident . $($toks:tt)*) => {
|
||||
f! { [$name] $name . $($toks)* }
|
||||
};
|
||||
}
|
||||
|
||||
/// Variant of the `f` macro producing a lambda which drops its first argument.
|
||||
#[macro_export]
|
||||
macro_rules! f_ {
|
||||
([$($name:ident),*] $($expr:tt)*) => {
|
||||
f! { [$($name),*] (_) $($expr)* }
|
||||
};
|
||||
|
||||
($name:ident . $($toks:tt)*) => {
|
||||
f_! { [$name] $name . $($toks)* }
|
||||
};
|
||||
|
||||
( { $name:ident . $($toks:tt)* } ) => {
|
||||
f_! { [$name] { $name . $($toks)* } }
|
||||
};
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
//! This module defines utilities for working with the `Option` type.
|
||||
|
||||
/// Adds mapping methods to the `Option` type.
|
||||
pub trait OptionOps {
|
||||
type Item;
|
||||
fn map_ref <U,F> (&self , f:F) -> Option<U> where F : FnOnce(&Self::Item) -> U;
|
||||
fn for_each <U,F> (self , f:F) where F : FnOnce(Self::Item) -> U;
|
||||
fn for_each_ref <U,F> (&self , f:F) where F : FnOnce(&Self::Item) -> U;
|
||||
}
|
||||
|
||||
impl<T> OptionOps for Option<T> {
|
||||
type Item = T;
|
||||
|
||||
fn map_ref<U,F>(&self, f:F) -> Option<U> where F : FnOnce(&Self::Item) -> U {
|
||||
self.as_ref().map(f)
|
||||
}
|
||||
|
||||
fn for_each<U,F>(self, f:F) where F : FnOnce(Self::Item) -> U {
|
||||
if let Some(x) = self { f(x); }
|
||||
}
|
||||
|
||||
fn for_each_ref<U,F>(&self, f:F) where F : FnOnce(&Self::Item) -> U {
|
||||
if let Some(x) = self { f(x); }
|
||||
}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
//! This module defines utilities for working with PhantomData.
|
||||
|
||||
use super::std_reexports::*;
|
||||
use derivative::Derivative;
|
||||
use shrinkwraprs::Shrinkwrap;
|
||||
|
||||
|
||||
|
||||
// ===================
|
||||
// === PhantomData ===
|
||||
// ===================
|
||||
|
||||
/// The following `PhantomData` implementations allow each argument to be non
|
||||
/// Sized. Unfortunately, this is not equivalent to `PhantomData<(T1,T2,...)>`,
|
||||
/// as tuple requires each arg to implement `Sized`.
|
||||
pub type PhantomData2<T1,T2> = PhantomData<(PhantomData <T1>, PhantomData<T2>)>;
|
||||
pub type PhantomData3<T1,T2,T3> = PhantomData2<PhantomData2<T1,T2>, PhantomData<T3>>;
|
||||
pub type PhantomData4<T1,T2,T3,T4> = PhantomData2<PhantomData3<T1,T2,T3>, PhantomData<T4>>;
|
||||
pub type PhantomData5<T1,T2,T3,T4,T5> = PhantomData2<PhantomData4<T1,T2,T3,T4>, PhantomData<T5>>;
|
||||
pub type PhantomData6<T1,T2,T3,T4,T5,T6> = PhantomData2<PhantomData5<T1,T2,T3,T4,T5>, PhantomData<T6>>;
|
||||
pub type PhantomData7<T1,T2,T3,T4,T5,T6,T7> = PhantomData2<PhantomData6<T1,T2,T3,T4,T5,T6>, PhantomData<T7>>;
|
||||
pub type PhantomData8<T1,T2,T3,T4,T5,T6,T7,T8> = PhantomData2<PhantomData7<T1,T2,T3,T4,T5,T6,T7>, PhantomData<T8>>;
|
||||
pub type PhantomData9<T1,T2,T3,T4,T5,T6,T7,T8,T9> = PhantomData2<PhantomData8<T1,T2,T3,T4,T5,T6,T7,T8>, PhantomData<T9>>;
|
||||
|
||||
|
||||
|
||||
// ===================
|
||||
// === WithPhantom ===
|
||||
// ===================
|
||||
|
||||
/// A wrapper adding a phantom type to a structure.
|
||||
#[derive(Derivative)]
|
||||
#[derive(Shrinkwrap)]
|
||||
#[shrinkwrap(mutable)]
|
||||
#[derivative(Clone (bound="T:Clone"))]
|
||||
#[derivative(Default (bound="T:Default"))]
|
||||
#[derivative(Debug (bound="T:Debug"))]
|
||||
pub struct WithPhantom<T, P=()> {
|
||||
#[shrinkwrap(main_field)]
|
||||
pub without_phantom: T,
|
||||
phantom: PhantomData<P>
|
||||
}
|
||||
|
||||
impl<T, P> WithPhantom<T, P> {
|
||||
pub fn new(without_phantom: T) -> Self {
|
||||
let phantom = PhantomData;
|
||||
Self { without_phantom, phantom }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ==========================
|
||||
// === PhantomConversions ===
|
||||
// ==========================
|
||||
|
||||
/// A utility for easy driving of type-level computations from value level. Often we've got some
|
||||
/// type level relations, like a few singleton types, and for each such type we've got an associated
|
||||
/// value. For example, we can define types `Int` and `Float` and associate with them
|
||||
/// `WebGlContext::Int` and `WebGlContext::Float` constants encoded as `GlEnum`. In order to convert
|
||||
/// `Int` or `Float` to the `GlEnum` we do not need the instance of the types, only the information
|
||||
/// what type it was. So we can define:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// impl From<PhantomData<Int>> for u32 {
|
||||
/// from(_:PhantomData<Int>>) {
|
||||
/// GlEnum(WebGlContext::Int)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// And use it like:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// let val = GlEnum::from(PhantomData::<Int>)
|
||||
/// ```
|
||||
///
|
||||
/// Using this utility we can always write the following code instead:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// let val = GlEnum::phantom_from::<Int>()
|
||||
/// ```
|
||||
pub trait PhantomConversions: Sized {
|
||||
fn phantom_into<P>() -> P where Self:PhantomInto<P> {
|
||||
PhantomData::<Self>.into()
|
||||
}
|
||||
fn phantom_from<P:PhantomInto<Self>>() -> Self {
|
||||
PhantomData::<P>.into()
|
||||
}
|
||||
}
|
||||
impl<T> PhantomConversions for T {}
|
||||
|
||||
/// Like `Into` but for phantom types.
|
||||
pub trait PhantomInto<T> = where PhantomData<Self>: Into<T>;
|
@ -1,78 +0,0 @@
|
||||
//! This module defines helpers and utilities for working with references.
|
||||
|
||||
// ============
|
||||
// === With ===
|
||||
// ============
|
||||
|
||||
/// Surprisingly useful function. Consider the following code:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// fn init(self) -> Self {
|
||||
/// let mut data = self.borrow_mut();
|
||||
/// ...
|
||||
/// self
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// It may not compile telling that the last line moves self out, however,
|
||||
/// borrow might be used there, when `data` is dropped and runs the destructor.
|
||||
///
|
||||
/// We can use this function to narrow-down the lifetimes. The following code
|
||||
/// compiles just fine:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// fn init(self) -> Self {
|
||||
/// with(self.borrow_mut(), |mut data| {
|
||||
/// ...
|
||||
/// });
|
||||
/// self
|
||||
/// }
|
||||
/// ```
|
||||
pub fn with<T, F: FnOnce(T) -> Out, Out>(t: T, f: F) -> Out { f(t) }
|
||||
|
||||
|
||||
|
||||
// =============
|
||||
// === ToRef ===
|
||||
// =============
|
||||
|
||||
/// Similar to `AsRef` but more specific and automatically implemented for every type. Allows for
|
||||
/// conversion `&T` to `&T` (identity) and `T` to `&T` for any type `T`. In contrast, `AsRef`
|
||||
/// requires explicit impls, so for example you cannot do `let t:&() = ().as_ref()`
|
||||
pub trait ToRef<T> where T:?Sized { fn to_ref(&self) -> &T; }
|
||||
impl<T> ToRef<T> for T where T:?Sized { fn to_ref(&self) -> &T { self } }
|
||||
impl<T> ToRef<T> for &T where T:?Sized { fn to_ref(&self) -> &T { self } }
|
||||
|
||||
// pub trait ToRef = ?Sized + HasRefValue + ToRef__<RefValue<Self>>;
|
||||
|
||||
pub trait HasRefValue where { type RefValue:?Sized; }
|
||||
impl <T> HasRefValue for T where T:?Sized { default type RefValue=T; }
|
||||
impl <T> HasRefValue for &T where T:?Sized { type RefValue=T; }
|
||||
|
||||
pub type RefValue<T> = <T as HasRefValue>::RefValue;
|
||||
|
||||
|
||||
|
||||
// =============
|
||||
// === Owned ===
|
||||
// =============
|
||||
|
||||
/// The owned version of a type. It would be super cool if Rust would allow us to automatically
|
||||
/// implement it for every type: `Owned<&T> = T` and `Owned<T> = T` if `T` was not a reference.
|
||||
/// Unfortunately, we need to implement it by hand for every type now.
|
||||
pub trait AsOwned {
|
||||
type Owned;
|
||||
}
|
||||
|
||||
/// Owned type family.
|
||||
pub type Owned<T> = <T as AsOwned>::Owned;
|
||||
|
||||
/// Converts type to its owned version.
|
||||
pub trait IntoOwned = AsOwned + Into<Owned<Self>>;
|
||||
|
||||
|
||||
// === Default Impls ===
|
||||
|
||||
impl<T> AsOwned for &T {
|
||||
type Owned = T;
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
//! This module reexports several commonly used types defined in the standard library.
|
||||
|
||||
// === Data ===
|
||||
|
||||
pub use std::any::Any;
|
||||
pub use std::borrow::Cow;
|
||||
pub use std::hash::Hash;
|
||||
pub use std::marker::PhantomData;
|
||||
pub use std::ops::Range;
|
||||
|
||||
|
||||
// === Format ===
|
||||
|
||||
pub use core::any::type_name;
|
||||
pub use core::fmt::Debug;
|
||||
pub use std::fmt::Display;
|
||||
pub use std::fmt;
|
||||
pub use std::iter::FromIterator;
|
||||
pub use std::iter;
|
||||
|
||||
|
||||
// === Data Operations ===
|
||||
|
||||
pub use std::ops::Deref;
|
||||
pub use std::ops::DerefMut;
|
||||
pub use std::ops::Index;
|
||||
pub use std::ops::IndexMut;
|
||||
|
||||
|
||||
// === Conversion ===
|
||||
|
||||
pub use std::convert::identity;
|
||||
pub use std::convert::TryFrom;
|
||||
pub use std::convert::TryInto;
|
||||
|
||||
|
||||
// === References ===
|
||||
|
||||
pub use std::cell::Cell;
|
||||
pub use std::cell::Ref;
|
||||
pub use std::cell::RefCell;
|
||||
pub use std::cell::RefMut;
|
||||
pub use std::rc::Rc;
|
||||
pub use std::rc::Weak;
|
||||
pub use std::slice::SliceIndex;
|
||||
pub use std::slice;
|
||||
|
||||
|
||||
// === Operators ===
|
||||
|
||||
pub use std::ops::Add;
|
||||
pub use std::ops::Div;
|
||||
pub use std::ops::Mul;
|
||||
pub use std::ops::Neg;
|
||||
pub use std::ops::Sub;
|
||||
|
||||
|
||||
// === Utils ===
|
||||
|
||||
pub use std::mem;
|
||||
|
||||
/// Alias for `Default::default()`.
|
||||
pub fn default<T:Default>() -> T {
|
||||
Default::default()
|
||||
}
|
@ -1,247 +0,0 @@
|
||||
//! This module defines several useful string variants, including copy-on-write and immutable
|
||||
//! implementations.
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::impls;
|
||||
use crate::clone::*;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use derive_more::*;
|
||||
|
||||
|
||||
|
||||
// ===========
|
||||
// === Str ===
|
||||
// ===========
|
||||
|
||||
/// Abstraction for any kind of string as an argument. Functions defined as
|
||||
/// `fn test<S:Str>(s: Str) { ... }` can be called with `String`, `&String`, and `&str` without
|
||||
/// requiring caller to know the implementation details. Moreover, the definition can decide if it
|
||||
/// needs allocation or not. Calling `s.as_ref()` will never allocate, while `s.into()` will
|
||||
/// allocate only when necessary.
|
||||
pub trait Str = Into<String> + AsRef<str>;
|
||||
|
||||
|
||||
|
||||
// =================
|
||||
// === CowString ===
|
||||
// =================
|
||||
|
||||
// === Definition ===
|
||||
|
||||
/// A copy-on-write String implementation. It is a newtype wrapper for `Cow<'static,str>` and
|
||||
/// provides many useful impls for efficient workflow. Use it whenever you want to store a string
|
||||
/// but you are not sure if the string will be allocated or not. This way you can store a static
|
||||
/// slice as long as you can and switch to allocated String on demand.
|
||||
#[derive(Clone,Debug,Default,Display)]
|
||||
pub struct CowString(Cow<'static,str>);
|
||||
|
||||
|
||||
// === Conversions From CowString ===
|
||||
|
||||
impls!{ From <&CowString> for String { |t| t.clone().into() } }
|
||||
impls!{ From <CowString> for String { |t| t.0.into() } }
|
||||
|
||||
|
||||
// === Conversions To CowString ===
|
||||
|
||||
impls!{ From <Cow<'static,str>> for CowString { |t| Self(t) } }
|
||||
impls!{ From <&Cow<'static,str>> for CowString { |t| Self(t.clone()) } }
|
||||
impls!{ From <&'static str> for CowString { |t| Self(t.into()) } }
|
||||
impls!{ From <String> for CowString { |t| Self(t.into()) } }
|
||||
impls!{ From <&String> for CowString { |t| t.to_string().into() } }
|
||||
impls!{ From <&CowString> for CowString { |t| t.clone() } }
|
||||
|
||||
|
||||
// === Instances ===
|
||||
|
||||
impl Deref for CowString {
|
||||
type Target = str;
|
||||
fn deref(&self) -> &str {
|
||||
self.0.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for CowString {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.deref()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ================
|
||||
// === ImString ===
|
||||
// ================
|
||||
|
||||
/// Immutable string implementation with a fast clone implementation.
|
||||
#[derive(Clone,CloneRef,Debug,Default,Eq,Hash,PartialEq)]
|
||||
pub struct ImString {
|
||||
content : Rc<String>
|
||||
}
|
||||
|
||||
impl ImString {
|
||||
/// Constructor.
|
||||
pub fn new(content:impl Into<String>) -> Self {
|
||||
let content = Rc::new(content.into());
|
||||
Self {content}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ImString {
|
||||
fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f,"{}",self.content)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ImString {
|
||||
type Target = str;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.content
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<ImString> for ImString {
|
||||
fn as_ref(&self) -> &ImString {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<String> for ImString {
|
||||
fn as_ref(&self) -> &String {
|
||||
self.content.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for ImString {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.content.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for ImString {
|
||||
fn from(t:String) -> Self {
|
||||
Self::new(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&String> for ImString {
|
||||
fn from(t:&String) -> Self {
|
||||
Self::new(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&&String> for ImString {
|
||||
fn from(t:&&String) -> Self {
|
||||
Self::new(*t)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for ImString {
|
||||
fn from(t:&str) -> Self {
|
||||
Self::new(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&&str> for ImString {
|
||||
fn from(t:&&str) -> Self {
|
||||
Self::new(*t)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<String> for ImString {
|
||||
fn eq(&self, other:&String) -> bool {
|
||||
self.content.as_ref().eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<ImString> for String {
|
||||
fn eq(&self, other:&ImString) -> bool {
|
||||
self.eq(other.content.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === Macros ===
|
||||
|
||||
/// Defines a newtype for `ImString`.
|
||||
#[macro_export]
|
||||
macro_rules! im_string_newtype {
|
||||
($($(#$meta:tt)* $name:ident),* $(,)?) => {$(
|
||||
$(#$meta)*
|
||||
#[derive(Clone,CloneRef,Debug,Default,Eq,Hash,PartialEq)]
|
||||
pub struct $name {
|
||||
content : ImString
|
||||
}
|
||||
|
||||
impl $name {
|
||||
/// Constructor.
|
||||
pub fn new(content:impl Into<ImString>) -> Self {
|
||||
let content = content.into();
|
||||
Self {content}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for $name {
|
||||
type Target = str;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.content
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<$name> for $name {
|
||||
fn as_ref(&self) -> &$name {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<ImString> for $name {
|
||||
fn as_ref(&self) -> &ImString {
|
||||
self.content.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<String> for $name {
|
||||
fn as_ref(&self) -> &String {
|
||||
self.content.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for $name {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.content.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for $name {
|
||||
fn from(t:String) -> Self {
|
||||
Self::new(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&String> for $name {
|
||||
fn from(t:&String) -> Self {
|
||||
Self::new(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&&String> for $name {
|
||||
fn from(t:&&String) -> Self {
|
||||
Self::new(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for $name {
|
||||
fn from(t:&str) -> Self {
|
||||
Self::new(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&&str> for $name {
|
||||
fn from(t:&&str) -> Self {
|
||||
Self::new(t)
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
//! Type related utilities.
|
||||
|
||||
use super::std_reexports::*;
|
||||
|
||||
|
||||
// ================
|
||||
// === Anything ===
|
||||
// ================
|
||||
|
||||
/// Placeholder type used to represent any value type. It is useful to define type-level relations
|
||||
/// like defining an unit with any quantity, let it be distance or mass.
|
||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||
pub struct Anything {}
|
||||
|
||||
|
||||
// ===================
|
||||
// === TypeDisplay ===
|
||||
// ===================
|
||||
|
||||
/// Like `Display` trait but for types. However, unlike `Display` it defaults to
|
||||
/// `impl::any::type_name` if not provided with explicit implementation.
|
||||
pub trait TypeDisplay {
|
||||
fn type_display() -> String;
|
||||
}
|
||||
|
||||
impl<T> TypeDisplay for T {
|
||||
default fn type_display() -> String {
|
||||
type_name::<Self>().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Formats the type for the user-facing output.
|
||||
pub fn type_display<T:TypeDisplay>() -> String {
|
||||
<T as TypeDisplay>::type_display()
|
||||
}
|
||||
|
||||
|
||||
// =============
|
||||
// === Value ===
|
||||
// =============
|
||||
|
||||
/// Defines relation between types and values, like between `True` and `true`.
|
||||
pub trait KnownTypeValue {
|
||||
|
||||
/// The value-level counterpart of this type-value.
|
||||
type Value;
|
||||
|
||||
/// The value of this type-value.
|
||||
fn value() -> Self::Value;
|
||||
}
|
||||
|
||||
pub type TypeValue<T> = <T as KnownTypeValue>::Value;
|
||||
|
||||
|
||||
|
||||
// =======================
|
||||
// === Type-level Bool ===
|
||||
// =======================
|
||||
|
||||
/// Type level `true` value.
|
||||
#[derive(Clone,Copy,Debug)]
|
||||
pub struct True {}
|
||||
|
||||
/// Type level `false` value.
|
||||
#[derive(Clone,Copy,Debug)]
|
||||
pub struct False {}
|
||||
|
||||
impl KnownTypeValue for True {
|
||||
type Value = bool;
|
||||
fn value() -> Self::Value {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl KnownTypeValue for False {
|
||||
type Value = bool;
|
||||
fn value() -> Self::Value {
|
||||
false
|
||||
}
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
//! This type defines Wrap / Unwrap utilities. Unwrap is like `Deref` but does not implement
|
||||
//! `impl<'a, T> Unwrap for &'a T` in order to make it less error prone. `Wrap` is like `pure` in
|
||||
//! applicative functors – if lifts a value to the specific type.
|
||||
|
||||
use crate::std_reexports::*;
|
||||
|
||||
// ===============
|
||||
// === Wrapper ===
|
||||
// ===============
|
||||
|
||||
/// Trait for any type which wraps other type. See docs of `Wrapper` to learn more.
|
||||
pub trait HasContent {
|
||||
type Content : ?Sized;
|
||||
}
|
||||
|
||||
/// Accessor for the wrapped value.
|
||||
pub type Content<T> = <T as HasContent>::Content;
|
||||
|
||||
/// Trait which enables `Sized` super-bound on the `Content` type.
|
||||
pub trait HasSizedContent = HasContent where Content<Self> : Sized;
|
||||
|
||||
/// Trait for objects which wrap values. Please note that this implements safe wrappers, so the
|
||||
/// object - value relation must be bijective.
|
||||
pub trait Wrapper = Wrap + ContentRef;
|
||||
|
||||
/// Wrapping utility for values.
|
||||
pub trait Wrap : HasSizedContent {
|
||||
/// Wraps the value and returns the wrapped type.
|
||||
fn wrap(t:Self::Content) -> Self;
|
||||
}
|
||||
|
||||
/// Unwrapping utility for wrapped types.
|
||||
///
|
||||
/// Please note that this trait is very similar to the Deref trait. However, there is a very
|
||||
/// important difference. Unlike `Deref`, there is no `impl<'a, T> Unwrap for &'a T` defined. The
|
||||
/// existence of such impl is very error prone when writing complex impls. The `Deref` docs warn
|
||||
/// about it explicitly: "[...] Because of this, Deref should only be implemented for smart pointers
|
||||
/// to avoid confusion.". As an example, consider the following code which contains infinite loop:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// pub trait HasId {
|
||||
/// fn id(&self) -> usize;
|
||||
/// }
|
||||
///
|
||||
/// // Notice the lack of bound `<T as Deref>::Target : HasId`
|
||||
/// impl<T:Deref> HasId for T {
|
||||
/// fn id(&self) -> usize {
|
||||
/// self.deref().id()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// And the correct version:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// pub trait HasId {
|
||||
/// fn id(&self) -> usize;
|
||||
/// }
|
||||
///
|
||||
/// // Notice the lack of bound `<T as Deref>::Target : HasId`
|
||||
/// impl<T:Deref> HasId for T where <T as Deref>::Target : HasId {
|
||||
/// fn id(&self) -> usize {
|
||||
/// self.deref().id()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Both versions compile fine, but the former loops for ever.
|
||||
pub trait ContentRef : HasContent {
|
||||
/// Unwraps this type to get the inner value.
|
||||
fn content(&self) -> &Self::Content;
|
||||
}
|
||||
|
||||
/// Runs a function on the reference to the content.
|
||||
pub trait WithContent : HasSizedContent {
|
||||
/// Runs a function on the reference to the content.
|
||||
fn with_content<F,T>(&self,f:F) -> T where F : FnOnce(&Content<Self>) -> T;
|
||||
}
|
||||
|
||||
/// Unwraps the content by consuming this value.
|
||||
pub trait Unwrap : HasSizedContent {
|
||||
/// Unwraps the content by consuming this value.
|
||||
fn unwrap(self) -> Self::Content;
|
||||
}
|
||||
|
||||
|
||||
// === Utils ===
|
||||
|
||||
/// Wraps the value and returns the wrapped type.
|
||||
pub fn wrap<T:Wrap>(t:T::Content) -> T {
|
||||
T::wrap(t)
|
||||
}
|
||||
|
||||
/// Provides reference to the content of this value.
|
||||
pub fn content<T:ContentRef>(t:&T) -> &T::Content {
|
||||
T::content(t)
|
||||
}
|
||||
|
||||
/// Unwrap the content by consuming this value.
|
||||
pub fn unwrap<T:Unwrap>(t:T) -> T::Content {
|
||||
T::unwrap(t)
|
||||
}
|
||||
|
||||
|
||||
// === Default Impls ===
|
||||
|
||||
impl<T:ContentRef + HasSizedContent> WithContent for T {
|
||||
fn with_content<F,S>(&self,f:F) -> S
|
||||
where F : FnOnce(&Content<Self>) -> S {
|
||||
f(self.content())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This should be implemented with the marker trait overlapping rules magic.
|
||||
// impl<T:Deref> Unwrap for T
|
||||
// where <T as Deref>::Target: Unwrap {
|
||||
// default fn unwrap(&self) -> &Self::Content {
|
||||
// self.deref().unwrap()
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// === Impls ===
|
||||
|
||||
impl<T:?Sized> HasContent for Rc<T> { type Content = T; }
|
||||
impl<T> Wrap for Rc<T> { fn wrap(t:T) -> Self { Rc::new(t) } }
|
||||
impl<T:?Sized> ContentRef for Rc<T> { fn content(&self) -> &Self::Content { self.deref() }}
|
||||
|
||||
impl HasContent for String { type Content = char; }
|
||||
impl Wrap for String { fn wrap(t:char) -> Self { t.to_string() } }
|
||||
|
||||
impl<T> HasContent for Vec<T> { type Content = T; }
|
||||
impl<T> Wrap for Vec<T> { fn wrap(t:T) -> Self { vec![t] } }
|
@ -1,19 +0,0 @@
|
||||
[package]
|
||||
name = "shapely"
|
||||
version = "0.1.0"
|
||||
authors = ["Enso Team <contact@luna-lang.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
shapely-macros = { version = "0.1.0" , path = "../macros" }
|
||||
paste = { version = "0.1" }
|
||||
derivative = { version = "1.0.3" }
|
||||
shrinkwraprs = { version = "0.3.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
enso-prelude = { version = "0.1.0" , path ="../../prelude" }
|
@ -1,45 +0,0 @@
|
||||
/// Computes a cartesian product of the provided input.
|
||||
///
|
||||
/// For the following expression:
|
||||
/// ```compile_fail
|
||||
/// cartesian!(f [g] [a b c] [x y z]);
|
||||
/// ```
|
||||
///
|
||||
/// It expands to:
|
||||
/// ```compile_fail
|
||||
/// f! { [g] [ [a x] [a y] [a z] [b x] [b y] [b z] [c x] [c y] [c z] ] }
|
||||
/// ```
|
||||
///
|
||||
/// If you provide underscore as second argument, it is skipped in the ouput macro:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// cartesian!(f _ [a b c] [x y z]);
|
||||
/// ```
|
||||
///
|
||||
/// Expands to:
|
||||
/// ```compile_fail
|
||||
/// f! { [ [a x] [a y] [a z] [b x] [b y] [b z] [c x] [c y] [c z] ] }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! cartesian {
|
||||
($f:tt [$($a:tt)*] [$($b:tt)*]) => {
|
||||
$crate::_cartesian_impl!{ $f [] [$($a)*] [$($b)*] [$($b)*] }
|
||||
};
|
||||
}
|
||||
|
||||
/// Internal helper for `cartesian` macro.
|
||||
#[macro_export]
|
||||
macro_rules! _cartesian_impl {
|
||||
([[$f:path]] $out:tt [] $b:tt $init_b:tt) => {
|
||||
$f!{ $out }
|
||||
};
|
||||
([[$f:path] $args:tt] $out:tt [] $b:tt $init_b:tt) => {
|
||||
$f!{ $args $out }
|
||||
};
|
||||
($f:tt $out:tt [$a:tt $($at:tt)*] [] $init_b:tt) => {
|
||||
$crate::_cartesian_impl!{ $f $out [$($at)*] $init_b $init_b }
|
||||
};
|
||||
($f:tt [$($out:tt)*] [$a:tt $($at:tt)*] [$b:tt $($bt:tt)*] $init_b:tt) => {
|
||||
$crate::_cartesian_impl!{ $f [$($out)* [$a $b]] [$a $($at)*] [$($bt)*] $init_b }
|
||||
};
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
//! Helper code meant to be used by the code generated through usage of macros
|
||||
//! from `shapely-macros` crate.
|
||||
|
||||
pub use shapely_macros::*;
|
||||
|
||||
use derivative::Derivative;
|
||||
use std::ops::Generator;
|
||||
use std::ops::GeneratorState;
|
||||
use std::pin::Pin;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
||||
|
||||
// ==========================
|
||||
// === GeneratingIterator ===
|
||||
// ==========================
|
||||
|
||||
/// Iterates over values yielded from the wrapped `Generator`.
|
||||
#[derive(Debug)]
|
||||
pub struct GeneratingIterator<G: Generator>(pub G);
|
||||
|
||||
impl<G> Iterator for GeneratingIterator<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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =====================
|
||||
// === EmptyIterator ===
|
||||
// =====================
|
||||
|
||||
/// An `Iterator` type that yields no values of the given type `T`.
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Debug,Default(bound=""))]
|
||||
pub struct EmptyIterator<T>(PhantomData<T>);
|
||||
|
||||
impl<T> EmptyIterator<T> {
|
||||
/// Create a new empty iterator.
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Iterator for EmptyIterator<T> {
|
||||
type Item = T;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =============
|
||||
// === Tests ===
|
||||
// =============
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn empty_iterator_works_for_any_type() {
|
||||
for elem in EmptyIterator::new() {
|
||||
elem: i32;
|
||||
}
|
||||
for elem in EmptyIterator::new() {
|
||||
elem: String;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generating_iterator_works() {
|
||||
let generator = || {
|
||||
yield 0;
|
||||
yield 1;
|
||||
yield 2;
|
||||
};
|
||||
let expected_numbers = vec!(0, 1, 2);
|
||||
let generator_iter = GeneratingIterator(generator);
|
||||
let collected_result: Vec<_> = generator_iter.collect();
|
||||
assert_eq!(collected_result, expected_numbers);
|
||||
}
|
||||
}
|
@ -1,405 +0,0 @@
|
||||
// README README README README README README README README README README README
|
||||
// README README README README README README README README README README README
|
||||
// README README README README README README README README README README README
|
||||
|
||||
// This library is in a very early stage. It will be refactored and improved
|
||||
// soon. It should not be reviewed now.
|
||||
|
||||
#![warn(unsafe_code)]
|
||||
#![warn(missing_copy_implementations)]
|
||||
#![warn(missing_debug_implementations)]
|
||||
#![feature(generators, generator_trait)]
|
||||
#![feature(specialization)]
|
||||
#![feature(type_ascription)]
|
||||
#![feature(overlapping_marker_traits)]
|
||||
|
||||
pub mod generator;
|
||||
pub mod shared;
|
||||
pub mod singleton;
|
||||
pub mod cartesian;
|
||||
|
||||
pub use shapely_macros::*;
|
||||
|
||||
pub use generator::EmptyIterator;
|
||||
pub use generator::GeneratingIterator;
|
||||
|
||||
use shrinkwraprs::Shrinkwrap;
|
||||
|
||||
|
||||
/// Replaces the first argument with the second one. It is useful when creating macros which match
|
||||
/// a pattern and you want to generate as many repetitions of a token as there was matches. For
|
||||
/// example, when matching `$($name:ident)*`, you may want to generate as many empty tuples as
|
||||
/// the number of names matched. You can do it by using `$(replace!{$name,()})*`.
|
||||
#[macro_export]
|
||||
macro_rules! replace {
|
||||
($a:tt,$b:tt) => {$b}
|
||||
}
|
||||
|
||||
/// Generates a newtype wrapper for the provided types. It also generates a lot of impls,
|
||||
/// including Copy, Clone, Debug, Default, Display, From, Into, Deref, and DerefMut.
|
||||
///
|
||||
/// For the following input:
|
||||
/// ```compile_fail
|
||||
/// newtype_copy! {
|
||||
/// AttributeIndex(usize)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The following code is generated:
|
||||
/// ```compile_fail
|
||||
/// #[derive(Copy, Clone, Debug, Default, Display, From, Into)]
|
||||
/// pub struct AttributeIndex(usize);
|
||||
/// impl Deref for AttributeIndex {
|
||||
/// type Target = usize;
|
||||
/// fn deref(&self) -> &Self::Target {
|
||||
/// &self.0
|
||||
/// }
|
||||
/// }
|
||||
/// impl DerefMut for AttributeIndex {
|
||||
/// fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
/// &mut self.0
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! newtype_copy {
|
||||
($( $(#$meta:tt)* $name:ident($type:ty); )*) => {$(
|
||||
$(#$meta)*
|
||||
#[derive(Copy,Clone,CloneRef,Debug,Default,Display,From,Into)]
|
||||
pub struct $name($type);
|
||||
|
||||
impl Deref for $name {
|
||||
type Target = $type;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for $name {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! derive_clone_plus {
|
||||
($name:ident) => {
|
||||
impl<T:Clone+Into<$name>> From<&T> for $name {
|
||||
fn from(t: &T) -> Self {
|
||||
t.clone().into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
macro_rules! extension_struct {
|
||||
($name:ident { $($field:ident : $field_type:ty),* }) => { paste::item! {
|
||||
|
||||
////// With_NAME_ //////
|
||||
|
||||
#[derive(Shrinkwrap)]
|
||||
#[shrinkwrap(mutable)]
|
||||
struct [<With $name>]<T>($($field_type),*, #[shrinkwrap(main_field)] T);
|
||||
|
||||
////// Has_NAME_ //////
|
||||
|
||||
pub trait [<Has $name>] {
|
||||
$(fn $field(&self) -> &$field_type;)*
|
||||
}
|
||||
|
||||
impl<T: [<Has $name Indirect>]>
|
||||
[<Has $name>] for T {
|
||||
$(fn $field(&self) -> &$field_type {
|
||||
[<Has $name Spec1>]::$field(self)
|
||||
})*
|
||||
}
|
||||
|
||||
////// Has_NAME_Indirect //////
|
||||
|
||||
pub trait [<Has $name Indirect>] {}
|
||||
|
||||
impl<T>
|
||||
[<Has $name Indirect>] for [<With $name>]<T> {}
|
||||
|
||||
impl<T>
|
||||
[<Has $name Indirect>] for T
|
||||
where T: Deref, <Self as Deref>::Target : [<Has $name>] {}
|
||||
|
||||
////// Has_NAME_Spec1 //////
|
||||
|
||||
trait [<Has $name Spec1>] {
|
||||
$(fn $field(&self) -> &$field_type;)*
|
||||
}
|
||||
|
||||
impl<T>
|
||||
[<Has $name Spec1>] for [<With $name>]<T> {
|
||||
$(fn $field(&self) -> &$field_type {
|
||||
&self.0
|
||||
})*
|
||||
}
|
||||
|
||||
impl<T: [<Has $name Indirect>]>
|
||||
[<Has $name Spec1>] for T {
|
||||
$(default fn $field(&self) -> &$field_type {
|
||||
[<Has $name Spec2>]::$field(self)
|
||||
})*
|
||||
}
|
||||
|
||||
////// Has_NAME_Spec2 //////
|
||||
|
||||
trait [<Has $name Spec2>] {
|
||||
$(fn $field(&self) -> &$field_type;)*
|
||||
}
|
||||
|
||||
impl<T: [<Has $name Indirect>]>
|
||||
[<Has $name Spec2>] for T {
|
||||
$(default fn $field(&self) -> &$field_type {
|
||||
unreachable!();
|
||||
})*
|
||||
}
|
||||
|
||||
impl<T>
|
||||
[<Has $name Spec2>] for T
|
||||
where T: Deref, <Self as Deref>::Target : [<Has $name>] {
|
||||
$(fn $field(&self) -> &$field_type {
|
||||
self.deref().$field()
|
||||
})*
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
extension_struct!(Label {
|
||||
label: String
|
||||
});
|
||||
|
||||
extension_struct!(Foo {
|
||||
t1: String
|
||||
});
|
||||
|
||||
|
||||
|
||||
// ==============
|
||||
// === WithID ===
|
||||
// ==============
|
||||
|
||||
struct WithID<T>(i32, T);
|
||||
|
||||
impl<T> Deref for WithID<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
|
||||
struct WithID2<T>(i32, T);
|
||||
|
||||
impl<T> Deref for WithID2<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
|
||||
//// === HasID ===
|
||||
//
|
||||
//pub trait HasID {
|
||||
// fn id(&self) -> &i32;
|
||||
//}
|
||||
//
|
||||
//impl<T: MarkerCtxForHasID> HasID for T {
|
||||
// fn id(&self) -> &i32 {
|
||||
// HasIDForVariantOrAny::id(self)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// === MarkerCtxForHasID ===
|
||||
//
|
||||
//pub trait MarkerCtxForHasID {}
|
||||
//
|
||||
//impl<T> MarkerCtxForHasID for WithID<T> {}
|
||||
//
|
||||
//impl<T> MarkerCtxForHasID for T
|
||||
//where T: Deref, <T as Deref>::Target : HasID {}
|
||||
//
|
||||
//
|
||||
//// === HasIDForVariantOrAny ===
|
||||
//
|
||||
//trait HasIDForVariantOrAny {
|
||||
// fn id(&self) -> &i32;
|
||||
//}
|
||||
//impl<T> HasIDForVariantOrAny for WithID<T> {
|
||||
// fn id(&self) -> &i32 {
|
||||
// &self.0
|
||||
// }
|
||||
//}
|
||||
//impl<T: MarkerCtxForHasID> HasIDForVariantOrAny for T {
|
||||
// default fn id(&self) -> &i32 {
|
||||
// HasIDForDerefOrAny::id(self)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// === HasIDForDerefOrAny ===
|
||||
//
|
||||
//trait HasIDForDerefOrAny {
|
||||
// fn id(&self) -> &i32;
|
||||
//}
|
||||
//impl<T> HasIDForDerefOrAny for T
|
||||
//where T: Deref, <Self as Deref>::Target : HasID {
|
||||
// fn id(&self) -> &i32 {
|
||||
// self.deref().id()
|
||||
// }
|
||||
//}
|
||||
//impl<T> HasIDForDerefOrAny for T {
|
||||
// default fn id(&self) -> &i32 {
|
||||
// unreachable!();
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// === HasID ===
|
||||
|
||||
pub trait HasID {
|
||||
fn id(&self) -> &i32;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////
|
||||
|
||||
#[overlappable]
|
||||
impl<T> HasID for T
|
||||
where T: Deref, <Self as Deref>::Target : HasID {
|
||||
fn id(&self) -> &i32 {
|
||||
self.deref().id()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: MarkerCtx_HasID> HasID for T {
|
||||
fn id(&self) -> &i32 {
|
||||
VariantOrAny_HasID::id(self)
|
||||
}
|
||||
}
|
||||
|
||||
// === MarkerCtx_HasID ===
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub trait MarkerCtx_HasID {}
|
||||
|
||||
impl<T> MarkerCtx_HasID for T
|
||||
where T: Deref, <T as Deref>::Target : HasID {}
|
||||
|
||||
// === VariantOrAny_HasID ===
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
trait VariantOrAny_HasID {
|
||||
fn id(&self) -> &i32;
|
||||
}
|
||||
|
||||
impl<T: MarkerCtx_HasID> VariantOrAny_HasID for T {
|
||||
default fn id(&self) -> &i32 {
|
||||
DerefOrAny_HasID::id(self)
|
||||
}
|
||||
}
|
||||
|
||||
// === DerefOrAny_HasID ===
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
trait DerefOrAny_HasID {
|
||||
fn id(&self) -> &i32;
|
||||
}
|
||||
impl<T> DerefOrAny_HasID for T
|
||||
where T: Deref, <Self as Deref>::Target : HasID {
|
||||
fn id(&self) -> &i32 {
|
||||
self.deref().id()
|
||||
}
|
||||
}
|
||||
impl<T> DerefOrAny_HasID for T {
|
||||
default fn id(&self) -> &i32 {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
|
||||
|
||||
//#[overlapping]
|
||||
//impl<T> HasID for WithID<T> {
|
||||
// fn id(&self) -> &i32 {
|
||||
// &self.0
|
||||
// }
|
||||
//}
|
||||
|
||||
impl<T> MarkerCtx_HasID for WithID<T> {}
|
||||
|
||||
impl<T> VariantOrAny_HasID for WithID<T> {
|
||||
fn id(&self) -> &i32 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
//// NON-CONFLICTING:
|
||||
//
|
||||
//trait HasFoo2 {
|
||||
// fn foo(&self) -> i32;
|
||||
//}
|
||||
//impl<T> HasFoo2 for T {
|
||||
// default fn foo(&self) -> i32 {
|
||||
// 7
|
||||
// }
|
||||
//}
|
||||
//impl<T> HasFoo2 for WithID<T> {
|
||||
// default fn foo(&self) -> i32 {
|
||||
// 8
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// CONFLICTING
|
||||
//
|
||||
//trait HasFoo3 {
|
||||
// fn foo(&self) -> i32;
|
||||
//}
|
||||
//impl<T> HasFoo3 for T
|
||||
// where T: Deref,
|
||||
// <T as Deref>::Target: HasFoo3 {
|
||||
// default fn foo(&self) -> i32 {
|
||||
// self.deref().foo()
|
||||
// }
|
||||
//}
|
||||
//impl<T> HasFoo3 for WithID<T> {
|
||||
// default fn foo(&self) -> i32 {
|
||||
// 8
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
// =============
|
||||
// === Usage ===
|
||||
// =============
|
||||
|
||||
struct _A(i32);
|
||||
|
||||
type _X = WithLabel<WithID<_A>>;
|
||||
|
||||
fn _test<T: HasID + HasLabel> (t: T) {
|
||||
println!("{:?}", t.label());
|
||||
println!("{:?}", t.id());
|
||||
}
|
||||
|
||||
fn _main() {
|
||||
let v1 = WithLabel("label1".to_string(), WithID(0, _A(1)));
|
||||
_test(v1); // THIS IS EXAMPLE USE CASE WHICH DOES NOT COMPILE
|
||||
|
||||
// println!("{}", 7.foo());
|
||||
}
|
@ -1,381 +0,0 @@
|
||||
/// This module implements the `shared` macro, an utility allowing for easy definition of
|
||||
/// `Rc<RefCell<...>>` wrappers.
|
||||
|
||||
|
||||
/// This macro provides an easy way to define secure `Rc<RefCell<...>>` wrappers for a given struct.
|
||||
///
|
||||
/// This macro accepts a body which is very similar to normal struct definition. There are a few
|
||||
/// notable differences:
|
||||
/// - The first token this macro accepts should be the name of the wrapped structure.
|
||||
/// - The implementation block does not have a name. It is always implemented for the struct.
|
||||
/// You are allowed to provide multiple impl blocks.
|
||||
///
|
||||
/// This macro traverses the definition and for each function, it generates a borrowing counterpart.
|
||||
/// It also handles the `new` function in a special way. Please note, that this macro generates
|
||||
/// only safe bindings. If your original function returns a reference, the generated code will fail.
|
||||
/// If you want to return references with some custom guard system, implement that outside of this
|
||||
/// macro usage.
|
||||
///
|
||||
/// For the given input:
|
||||
/// ```compile_fail
|
||||
/// shared! { Uniform
|
||||
///
|
||||
/// #[derive(Clone,Copy,Debug)]
|
||||
/// pub struct UniformData<Value> {
|
||||
/// value: Value,
|
||||
/// dirty: bool,
|
||||
/// }
|
||||
///
|
||||
/// impl<Value:UniformValue> {
|
||||
/// /// Constructor.
|
||||
/// pub fn new(value:Value) -> Self {
|
||||
/// let dirty = false;
|
||||
/// Self {value,dirty}
|
||||
/// }
|
||||
///
|
||||
/// /// Checks whether the uniform was changed and not yet updated.
|
||||
/// pub fn check_dirty(&self) -> bool {
|
||||
/// self.dirty
|
||||
/// }
|
||||
///
|
||||
/// /// Modifies the value stored by the uniform.
|
||||
/// pub fn modify<F:FnOnce(&mut Value)>(&mut self, f:F) {
|
||||
/// self.set_dirty();
|
||||
/// f(&mut self.value);
|
||||
/// }
|
||||
/// }}
|
||||
/// ```
|
||||
///
|
||||
/// The following output will be generated:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// #[derive(Clone,Copy,Debug)]
|
||||
/// pub struct UniformData<Value> {
|
||||
/// value: Value,
|
||||
/// dirty: bool,
|
||||
/// }
|
||||
///
|
||||
/// impl<Value:UniformValue> for UniformData<Value> {
|
||||
/// #[doc = r###"Constructor."###]
|
||||
/// pub fn new(value:Value) -> Self {
|
||||
/// let dirty = false;
|
||||
/// Self {value,dirty}
|
||||
/// }
|
||||
///
|
||||
/// #[doc = r###"Checks whether the uniform was changed and not yet updated."###]
|
||||
/// pub fn check_dirty(&self) -> bool {
|
||||
/// self.dirty
|
||||
/// }
|
||||
///
|
||||
/// #[doc = r###"Modifies the value stored by the uniform."###]
|
||||
/// pub fn modify<F:FnOnce(&mut Value)>(&mut self, f:F) {
|
||||
/// self.set_dirty();
|
||||
/// f(&mut self.value);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Clone,Copy,Debug)]
|
||||
/// pub struct Uniform<Value> {
|
||||
/// rc: Rc<RefCell<UniformData<Value>>>
|
||||
/// }
|
||||
///
|
||||
/// impl<Value:UniformValue> for Uniform<Value> {
|
||||
/// #[doc = r###"Constructor."###]
|
||||
/// pub fn new(value:Value) -> Self {
|
||||
/// let rc = Rc::new(RefCell::new(UniformData::new(value)));
|
||||
/// Self {rc}
|
||||
/// }
|
||||
///
|
||||
/// #[doc = r###"Checks whether the uniform was changed and not yet updated."###]
|
||||
/// pub fn check_dirty(&self) -> bool {
|
||||
/// self.rc.borrow.check_dirty()
|
||||
/// }
|
||||
///
|
||||
/// #[doc = r###"Modifies the value stored by the uniform."###]
|
||||
/// pub fn modify<F:FnOnce(&mut Value)>(&self, f:F) {
|
||||
/// self.borrow_mut().modify(f)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// **Note**
|
||||
/// Both the implementation as well as usage syntax of this macro will be nicer if it was
|
||||
/// implemented as procedural macro. However, no IDE supports expansion of procedural macros
|
||||
/// currently, so it was implemented as macro rules instead.
|
||||
#[macro_export]
|
||||
macro_rules! shared {
|
||||
($name:ident $($in:tt)*) => {
|
||||
$crate::angles_to_brackets_shallow! { shared_bracket [$name] $($in)* }
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! shared_bracket_impl {
|
||||
([impl [$($impl_params:tt)*] $name:ident $name_mut:ident $([$($params:tt)*])?] [
|
||||
$(
|
||||
$(#[$($meta:tt)*])*
|
||||
$acc:vis fn $fn_name:ident
|
||||
$([$($fn_params:tt)*])? ($($fn_args:tt)*) $(-> $fn_type:ty)? $(where $($wt1:ty : $wt2:path),* )? {
|
||||
$($fn_body:tt)*
|
||||
}
|
||||
)*
|
||||
]) => {
|
||||
impl <$($impl_params)*> $name_mut $(<$($params)*>)? {
|
||||
$(
|
||||
$(#[$($meta)*])*
|
||||
$acc fn $fn_name $(<$($fn_params)*>)*
|
||||
($($fn_args)*) $(-> $fn_type)? $(where $($wt1 : $wt2),* )? {$($fn_body)*}
|
||||
)*
|
||||
}
|
||||
|
||||
impl <$($impl_params)*> $name $(<$($params)*>)? {
|
||||
$($crate::shared_bracket_fn! {
|
||||
$name_mut :: $(#[$($meta)*])*
|
||||
$acc fn $fn_name [$($($fn_params)*)*] ($($fn_args)*) $(-> $fn_type)? $(where $($wt1 : $wt2),* )?
|
||||
})*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! shared_bracket_fn {
|
||||
( $base:ident :: $(#[$($meta:tt)*])* $acc:vis fn new $([$($params:tt)*])?
|
||||
($($arg:ident : $arg_type:ty),*) $(-> $type:ty)? $(where $($wt1:ty : $wt2:path),* )? ) => {
|
||||
$(#[$($meta)*])*
|
||||
$acc fn new $(<$($params)*>)* ($($arg : $arg_type),*) $(-> $type)? $(where $($wt1 : $wt2),* )? {
|
||||
Self { rc: Rc::new(RefCell::new($base::new($($arg),*))) }
|
||||
}
|
||||
};
|
||||
( $base:ident :: $(#[$($meta:tt)*])* $acc:vis fn $name:ident $([$($params:tt)*])?
|
||||
(&self $(,$($arg:ident : $arg_type:ty),+)?) $(-> $type:ty)? $(where $($wt1:ty : $wt2:path),* )? ) => {
|
||||
$(#[$($meta)*])*
|
||||
$acc fn $name $(<$($params)*>)* (&self $(,$($arg : $arg_type),*)?) $(-> $type)? $(where $($wt1 : $wt2),* )? {
|
||||
self.rc.borrow().$name($($($arg),*)?)
|
||||
}
|
||||
};
|
||||
( $base:ident :: $(#[$($meta:tt)*])* $acc:vis fn $name:ident $([$($params:tt)*])?
|
||||
(&mut self $(,$($arg:ident : $arg_type:ty),+)?) $(-> $type:ty)? $(where $($wt1:ty : $wt2:path),* )? ) => {
|
||||
$(#[$($meta)*])*
|
||||
$acc fn $name $(<$($params)*>)* (&self $(,$($arg : $arg_type),*)?) $(-> $type)? $(where $($wt1 : $wt2),* )? {
|
||||
self.rc.borrow_mut().$name($($($arg),*)?)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! shared_bracket_normalized {
|
||||
( [$name:ident] [
|
||||
$(#[$($meta:tt)*])*
|
||||
$(##[$($imeta:tt)*])*
|
||||
pub struct $name_mut:ident $params:tt {
|
||||
$($(#[$($field_meta:tt)*])* $field:ident : $field_type:ty),* $(,)?
|
||||
}
|
||||
|
||||
$(impl $([$($impl_params:tt)*])? {$($impl_body:tt)*})*
|
||||
]) => {
|
||||
$crate::shared_struct! {
|
||||
$(#[$($meta)*])*
|
||||
$(##[$($imeta)*])*
|
||||
pub struct $name $name_mut $params {
|
||||
$($(#[$($field_meta)*])* $field : $field_type),*
|
||||
}
|
||||
}
|
||||
|
||||
$($crate::angles_to_brackets_shallow! {shared_bracket_impl
|
||||
[impl [$($($impl_params)*)?] $name $name_mut $params] $($impl_body)*
|
||||
})*
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! shared_struct {
|
||||
(
|
||||
$(#[$($meta:tt)*])*
|
||||
$(##[$($imeta:tt)*])*
|
||||
pub struct $name:ident $name_mut:ident [$($params:tt)*] {
|
||||
$($(#[$($field_meta:tt)*])* $field:ident : $field_type:ty),* $(,)?
|
||||
}
|
||||
) => {
|
||||
$(#[$($meta)*])*
|
||||
#[derive(CloneRef)]
|
||||
pub struct $name <$($params)*> { rc: Rc<RefCell<$name_mut<$($params)*>>> }
|
||||
|
||||
$(#[$($meta)*])*
|
||||
$(#[$($imeta)*])*
|
||||
pub struct $name_mut <$($params)*> { $($(#[$($field_meta)*])* $field : $field_type),* }
|
||||
|
||||
impl<$($params)*> Clone for $name <$($params)*> {
|
||||
fn clone(&self) -> Self {
|
||||
let rc = self.rc.clone();
|
||||
Self {rc}
|
||||
}
|
||||
}
|
||||
|
||||
paste::item! {
|
||||
$(#[$($meta)*])*
|
||||
#[derive(CloneRef)]
|
||||
pub struct [<Weak $name>] <$($params)*> { weak: Weak<RefCell<$name_mut<$($params)*>>> }
|
||||
|
||||
impl<$($params)*> Clone for [<Weak $name>] <$($params)*> {
|
||||
fn clone(&self) -> Self {
|
||||
let weak = self.weak.clone();
|
||||
Self {weak}
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($params)*> [<Weak $name>] <$($params)*> {
|
||||
/// Attempts to upgrade the weak pointer to an rc, delaying dropping of the inner
|
||||
/// value if successful.
|
||||
pub fn upgrade(&self) -> Option<$name <$($params)*>> {
|
||||
self.weak.upgrade().map(|rc| $name {rc})
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($params)*> WeakElement for [<Weak $name>] <$($params)*> {
|
||||
type Strong = $name <$($params)*> ;
|
||||
|
||||
fn new(view: &Self::Strong) -> Self {
|
||||
view.downgrade()
|
||||
}
|
||||
|
||||
fn view(&self) -> Option<Self::Strong> {
|
||||
self.upgrade()
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($params)*> $name <$($params)*> {
|
||||
/// Downgrade the reference to weak ref.
|
||||
pub fn downgrade(&self) -> [<Weak $name>] <$($params)*> {
|
||||
let weak = Rc::downgrade(&self.rc);
|
||||
[<Weak $name>] {weak}
|
||||
}
|
||||
|
||||
/// Call operation with borrowed data. Should be use in implementation of wrapper
|
||||
/// only.
|
||||
fn with_borrowed<F,R>(&self, operation:F) -> R
|
||||
where F : FnOnce(&mut $name_mut<$($params)*>) -> R {
|
||||
operation(&mut self.rc.borrow_mut())
|
||||
}
|
||||
|
||||
/// Wraps given data object into a shared handle.
|
||||
pub fn new_from_data(data:$name_mut<$($params)*>) -> Self {
|
||||
Self {rc:Rc::new(RefCell::new(data))}
|
||||
}
|
||||
|
||||
/// Check if the shared pointer points to the same struct as `other`.
|
||||
pub fn identity_equals(&self, other:&Self) -> bool {
|
||||
Rc::ptr_eq(&self.rc,&other.rc)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! angles_to_brackets_shallow {
|
||||
($f:ident $f_arg:tt $($in:tt)*) => {
|
||||
$crate::_angles_to_brackets_shallow! { $f $f_arg [] [] [] $($in)* }
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! _angles_to_brackets_shallow {
|
||||
( $f:ident $f_arg:tt [] [$($out:tt)*] [] ) => { $crate::$f! { $f_arg [$($out)*] } };
|
||||
( $f:ident $f_arg:tt [] [$($out:tt)*] [$($cout:tt)*] ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] [$($out)* $($cout)*] [] } };
|
||||
( $f:ident $f_arg:tt [] [$($out:tt)*] [$($cout:tt)*] < $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [.] [$($out)* $($cout)*] [] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] << $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [. .] $out [$($cout)* <] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] <<< $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [. . .] $out [$($cout)* <<] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] <<<< $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [. . . .] $out [$($cout)* <<<] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] <<<<< $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [. . . . .] $out [$($cout)* <<<<] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [$($depth:tt)*] $out:tt [$($cout:tt)*] < $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [$($depth)* .] $out [$($cout)* <] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [$($depth:tt)*] $out:tt [$($cout:tt)*] << $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [$($depth)* . .] $out [$($cout)* <<] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [$($depth:tt)*] $out:tt [$($cout:tt)*] <<< $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [$($depth)* . . .] $out [$($cout)* <<<] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [$($depth:tt)*] $out:tt [$($cout:tt)*] <<<< $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [$($depth)* . . . .] $out [$($cout)* <<<<] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [$($depth:tt)*] $out:tt [$($cout:tt)*] <<<<< $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [$($depth)* . . . . .] $out [$($cout)* <<<<<] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [. $($depth:tt)*] $out:tt [$($cout:tt)*] -> $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [. $($depth)*] $out [$($cout)* ->] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [.] [$($out:tt)*] $cout:tt > $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] [$($out)* $cout] [] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [. .] [$($out:tt)*] [$($cout:tt)*] >> $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] [$($out)* [$($cout)* >]] [] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [. . .] [$($out:tt)*] [$($cout:tt)*] >>> $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] [$($out)* [$($cout)* >>]] [] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [. . . .] [$($out:tt)*] [$($cout:tt)*] >>>> $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] [$($out)* [$($cout)* >>>]] [] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [. . . . .] [$($out:tt)*] [$($cout:tt)*] >>>>> $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] [$($out)* [$($cout)* >>>>]] [] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [. $($depth:tt)*] $out:tt [$($cout:tt)*] > $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [$($depth)*] $out [$($cout)* >] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [. . $($depth:tt)*] $out:tt [$($cout:tt)*] >> $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [$($depth)*] $out [$($cout)* >>] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [. . . $($depth:tt)*] $out:tt [$($cout:tt)*] >>> $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [$($depth)*] $out [$($cout)* >>>] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [. . . . $($depth:tt)*] $out:tt [$($cout:tt)*] >>>> $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [$($depth)*] $out [$($cout)* >>>>] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [. . . . . $($depth:tt)*] $out:tt [$($cout:tt)*] >>>>> $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [$($depth)*] $out [$($cout)* >>>>>] $($rest)* } };
|
||||
|
||||
// Function output handling
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $t26:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $t26 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $t26:tt $t27:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $t26 $t27 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $t26:tt $t27:tt $t28:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $t26 $t27 $t28 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $t26:tt $t27:tt $t28:tt $t29:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $t26 $t27 $t28 $t29 {$($b)*}] $($rest)* } };
|
||||
( $f:ident $f_arg:tt [] $out:tt [$($cout:tt)*] -> $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $t26:tt $t27:tt $t28:tt $t29:tt $t30:tt {$($b:tt)*} $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg [] $out [$($cout)* -> $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $t26 $t27 $t28 $t29 $t30 {$($b)*}] $($rest)* } };
|
||||
|
||||
// Any token handling
|
||||
( $f:ident $f_arg:tt $depth:tt $out:tt [$($cout:tt)*] $t:tt $($rest:tt)* ) => { $crate::_angles_to_brackets_shallow! { $f $f_arg $depth $out [$($cout)* $t] $($rest)* } };
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! shared_bracket {
|
||||
([$name:ident] [$($in:tt)*]) => {
|
||||
$crate::normalize_input! { shared_bracket_normalized [$name] $($in)* }
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! normalize_input {
|
||||
($f:ident $f_args:tt $($in:tt)*) => {
|
||||
$crate::_normalize_input! { $f $f_args [] $($in)* }
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! _normalize_input {
|
||||
// Finish.
|
||||
( $f:ident $f_args:tt $out:tt ) => {
|
||||
$crate::$f! { $f_args $out }
|
||||
};
|
||||
|
||||
// Structs.
|
||||
( $f:ident $f_args:tt [$($out:tt)*]
|
||||
$(#[$($meta:tt)*])*
|
||||
pub struct $name:tt $([$($params:tt)*])? {$($body:tt)*}
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
$crate::_normalize_input! { $f $f_args
|
||||
[$($out)*
|
||||
$(#[$($meta)*])*
|
||||
pub struct $name [$($($params)*)?] {$($body)*}
|
||||
] $($rest)* }
|
||||
};
|
||||
|
||||
// Any token.
|
||||
( $f:ident $f_args:tt [$($out:tt)*] $in:tt $($rest:tt)* ) => {
|
||||
$crate::_normalize_input! { $f $f_args [$($out)* $in] $($rest)* }
|
||||
};
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
//! This module defines helpers for defining singletons and associated enum types. A singleton is
|
||||
//! a type with one possible value. It is used mainly for a type level programming purposes.
|
||||
|
||||
/// Defines singleton types. For the following input:
|
||||
/// ```compile_fail
|
||||
/// define_singletons!{
|
||||
/// /// A Foo!
|
||||
/// Foo,
|
||||
/// /// A Bar!
|
||||
/// Bar,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// It expands to:
|
||||
///
|
||||
/// ```
|
||||
/// #[allow(missing_docs)]
|
||||
/// #[derive(Copy, Clone, Debug)]
|
||||
/// #[doc = r###"A Foo!"###]
|
||||
/// pub struct Foo;
|
||||
/// impl Default for Foo {
|
||||
/// fn default() -> Self {
|
||||
/// Self
|
||||
/// }
|
||||
/// }
|
||||
/// #[allow(missing_docs)]
|
||||
/// #[derive(Copy, Clone, Debug)]
|
||||
/// #[doc = r###"A Bar!"###]
|
||||
/// pub struct Bar;
|
||||
/// impl Default for Bar {
|
||||
/// fn default() -> Self {
|
||||
/// Self
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! define_singletons {
|
||||
( $( $(#$meta:tt)* $name:ident ),* $(,)? ) => {$(
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy,Clone,Debug,PartialEq,Eq)]
|
||||
$(#$meta)*
|
||||
pub struct $name;
|
||||
|
||||
impl Default for $name {
|
||||
fn default() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
/// Defines an associated enum type for predefined singletons.
|
||||
///
|
||||
/// For the following input:
|
||||
/// ```compile_fail
|
||||
/// define_singleton_enum!{
|
||||
/// MyEnum {
|
||||
/// /// A Foo!
|
||||
/// Foo,
|
||||
/// /// A Bar!
|
||||
/// Bar,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// It expands to:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// #[allow(missing_docs)]
|
||||
/// #[derive(Copy, Clone, Debug)]
|
||||
/// pub enum MyEnum {
|
||||
/// #[doc = r###"A Foo!"###]
|
||||
/// Foo,
|
||||
/// #[doc = r###"A Bar!"###]
|
||||
/// Bar,
|
||||
/// }
|
||||
/// impl From<Foo> for MyEnum {
|
||||
/// fn from(_: Foo) -> Self {
|
||||
/// Self::Foo
|
||||
/// }
|
||||
/// }
|
||||
/// impl From<PhantomData<Foo>> for MyEnum {
|
||||
/// fn from(_: PhantomData<Foo>) -> Self {
|
||||
/// Self::Foo
|
||||
/// }
|
||||
/// }
|
||||
/// impl From<Bar> for MyEnum {
|
||||
/// fn from(_: Bar) -> Self {
|
||||
/// Self::Bar
|
||||
/// }
|
||||
/// }
|
||||
/// impl From<PhantomData<Bar>> for MyEnum {
|
||||
/// fn from(_: PhantomData<Bar>) -> Self {
|
||||
/// Self::Bar
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! define_singleton_enum_from {
|
||||
(
|
||||
$(#$meta:tt)*
|
||||
$name:ident {
|
||||
$( $(#$field_meta:tt)* $field:ident ),* $(,)?
|
||||
}
|
||||
) => {
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy,Clone,Debug,PartialEq,Eq)]
|
||||
$(#$meta)*
|
||||
pub enum $name {
|
||||
$( $(#$field_meta)* $field ),*
|
||||
}
|
||||
|
||||
$(
|
||||
impl From<$field> for $name {
|
||||
fn from(_:$field) -> Self {
|
||||
Self::$field
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PhantomData<$field>> for $name {
|
||||
fn from(_:PhantomData<$field>) -> Self {
|
||||
Self::$field
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines singletons and an associated enum type.
|
||||
/// It expands to the same as `define_singletons` and `define_singleton_enum_from`.
|
||||
#[macro_export]
|
||||
macro_rules! define_singleton_enum {
|
||||
(
|
||||
$(#$meta:tt)*
|
||||
$name:ident {
|
||||
$( $(#$field_meta:tt)* $field:ident ),* $(,)?
|
||||
}
|
||||
) => {
|
||||
$crate::define_singletons! { $($(#$field_meta)* $field),* }
|
||||
$crate::define_singleton_enum_from! { $(#$meta)* $name {$($(#$field_meta)* $field),*}}
|
||||
}
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
#![feature(generators)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use shapely::*;
|
||||
|
||||
|
||||
|
||||
// =============
|
||||
// === Utils ===
|
||||
// =============
|
||||
|
||||
/// To fail compilation if `T` is not `IntoIterator`.
|
||||
fn is_into_iterator<T: IntoIterator>(){}
|
||||
|
||||
fn to_vector<T>(t: T) -> Vec<T::Item>
|
||||
where T : IntoIterator,
|
||||
T::Item: Copy {
|
||||
t.into_iter().collect()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =====================================
|
||||
// === Struct with single type param ===
|
||||
// =====================================
|
||||
|
||||
#[derive(Iterator, IteratorMut, Eq, PartialEq, Debug)]
|
||||
pub struct PairTT<T>(T, T);
|
||||
|
||||
#[test]
|
||||
fn derive_iterator_single_t() {
|
||||
is_into_iterator::<& PairTT<i32>>();
|
||||
is_into_iterator::<&mut PairTT<i32>>();
|
||||
|
||||
let get_pair = || PairTT(4, 49);
|
||||
|
||||
// just collect values
|
||||
let pair = get_pair();
|
||||
let collected = pair.iter().copied().collect::<Vec<i32>>();
|
||||
assert_eq!(collected, vec![4, 49]);
|
||||
|
||||
// IntoIterator for &mut Val
|
||||
let mut pair = get_pair();
|
||||
for i in &mut pair {
|
||||
*i = *i + 1
|
||||
}
|
||||
assert_eq!(pair, PairTT(5, 50));
|
||||
|
||||
// iter_mut
|
||||
for i in pair.iter_mut() {
|
||||
*i = *i + 1
|
||||
}
|
||||
assert_eq!(pair, PairTT(6, 51));
|
||||
|
||||
// IntoIterator for & Val
|
||||
let pair = get_pair(); // not mut anymore
|
||||
let mut sum = 0;
|
||||
for i in &pair {
|
||||
sum += i;
|
||||
}
|
||||
assert_eq!(sum, pair.0 + pair.1)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===================================
|
||||
// === Struct with two type params ===
|
||||
// ===================================
|
||||
|
||||
#[derive(Iterator, IteratorMut, Eq, PartialEq, Debug)]
|
||||
pub struct PairUV<U,V>(U,V);
|
||||
|
||||
#[test]
|
||||
fn two_params() {
|
||||
// verify that iter uses only the last type param field
|
||||
let pair = PairUV(5, 10);
|
||||
assert_eq!(to_vector(pair.iter().copied()), vec![10]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ======================================
|
||||
// === Struct without any type params ===
|
||||
// ======================================
|
||||
|
||||
#[derive(Iterator, Eq, PartialEq, Debug)]
|
||||
pub struct Monomorphic(i32);
|
||||
|
||||
#[test]
|
||||
fn no_params() {
|
||||
// `derive(Iterator)` is no-op for structures with no type parameters.
|
||||
// We just make sure that it does not cause compilation error.
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ========================
|
||||
// === Enumeration Type ===
|
||||
// ========================
|
||||
|
||||
#[derive(Iterator)]
|
||||
#[warn(dead_code)] // value is never read and shouldn't be
|
||||
pub struct Unrecognized{ pub value : String }
|
||||
|
||||
#[derive(Iterator)]
|
||||
pub enum Foo<U, T> {
|
||||
Con1(PairUV<U, T>),
|
||||
Con2(PairTT<T>),
|
||||
Con3(Unrecognized)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_is_into_iterator() {
|
||||
is_into_iterator::<&Foo<i32, i32>>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_iter1() {
|
||||
let v = Foo::Con1(PairUV(4, 50));
|
||||
let mut v_iter = v.into_iter();
|
||||
assert_eq!(*v_iter.next().unwrap(),50);
|
||||
assert!(v_iter.next().is_none());
|
||||
}
|
||||
#[test]
|
||||
fn enum_iter2() {
|
||||
let v: Foo<i32, i32> = Foo::Con2(PairTT(6,60));
|
||||
let mut v_iter = v.into_iter();
|
||||
assert_eq!(*v_iter.next().unwrap(),6);
|
||||
assert_eq!(*v_iter.next().unwrap(),60);
|
||||
assert!(v_iter.next().is_none());
|
||||
}
|
||||
#[test]
|
||||
fn enum_iter3() {
|
||||
let v: Foo<i32, i32> = Foo::Con3(Unrecognized{value:"foo".into()});
|
||||
let mut v_iter = v.into_iter();
|
||||
assert!(v_iter.next().is_none());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =======================
|
||||
// === Dependent Types ===
|
||||
// =======================
|
||||
|
||||
#[derive(Iterator)]
|
||||
#[derive(IteratorMut)]
|
||||
pub struct DependentTest<U, T> {
|
||||
a:T,
|
||||
b:(T,U,PairUV<U, T>),
|
||||
// is never used, as it doesn't depend on `T` (last param)
|
||||
#[allow(dead_code)]
|
||||
c:PairTT<U>,
|
||||
d:(i32, Option<Vec<T>>),
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dependent_test_iter() {
|
||||
let val = DependentTest{
|
||||
a : 1,
|
||||
b : (2,3,PairUV(4,5)),
|
||||
c : PairTT(6,6),
|
||||
d : (7, Some(vec![8,9])),
|
||||
};
|
||||
let mut v_iter = val.into_iter();
|
||||
assert_eq!(*v_iter.next().unwrap(), 1);
|
||||
assert_eq!(*v_iter.next().unwrap(), 2);
|
||||
// 3 is `U` in tuple
|
||||
// 4 is `U` in <U,T> pair
|
||||
assert_eq!(*v_iter.next().unwrap(), 5);
|
||||
// 7 is `i32` in tuple
|
||||
assert_eq!(*v_iter.next().unwrap(), 8);
|
||||
assert_eq!(*v_iter.next().unwrap(), 9);
|
||||
assert!(v_iter.next().is_none());
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
// This module contains dead code. Its purpose is making sure that it compiles
|
||||
#![allow(dead_code)]
|
||||
|
||||
use enso_prelude::*;
|
||||
|
||||
#[derive(Clone,CloneRef)] struct StructUnit;
|
||||
|
||||
#[derive(Clone,CloneRef)] struct StructUnnamedEmpty();
|
||||
|
||||
#[derive(Clone,CloneRef)] struct StructUnnamed(Rc<i32>,Rc<String>);
|
||||
|
||||
#[derive(Clone,CloneRef)] struct StructNamedEmpty{}
|
||||
|
||||
#[derive(Clone,CloneRef)] struct StructNamed{named0:Rc<i32>,named1:Rc<String>}
|
||||
|
||||
#[derive(Clone,CloneRef)] enum EnumEmpty {}
|
||||
|
||||
#[derive(Clone,CloneRef)] enum Enum {
|
||||
VariantUnit,
|
||||
VariantNamedEmpty {},
|
||||
VariantNamed {named0:Rc<i32>,named1:Rc<String>},
|
||||
VariantUnnamedEmpty(),
|
||||
VariantUnnamed(Rc<i32>,Rc<String>),
|
||||
}
|
||||
|
||||
#[derive(CloneRef,Derivative)]
|
||||
#[derivative(Clone(bound=""))]
|
||||
struct StructUnnamedUnbound<T>(Rc<T>);
|
||||
|
||||
#[derive(CloneRef,Clone)]
|
||||
#[clone_ref(bound="T:CloneRef")]
|
||||
struct StructUnnamedBound<T>(T);
|
||||
|
||||
#[derive(CloneRef,Clone)]
|
||||
#[clone_ref(bound="T:CloneRef,U:CloneRef")]
|
||||
struct StructUnnamedBoundTwoPatams<T,U>(T,U);
|
||||
|
||||
#[derive(Clone,CloneRef)]
|
||||
#[clone_ref(bound="T:Clone+Display")]
|
||||
struct StructBoundGeneric<T:Display>(Rc<T>);
|
||||
|
||||
#[derive(CloneRef,Derivative)]
|
||||
#[derivative(Clone(bound=""))]
|
||||
// Note: CloneRef "knows" about `Display` bound.
|
||||
struct StructGenericLifetime<'t>(Rc<&'t String>);
|
||||
|
||||
#[derive(CloneRef,Derivative)]
|
||||
#[derivative(Clone(bound=""))]
|
||||
struct StructWhereClause<T>(Rc<T>) where T:Debug;
|
||||
|
||||
#[derive(CloneRef,Clone)]
|
||||
#[clone_ref(bound="T:CloneRef")]
|
||||
// Here derive macro must correctly merge user-provided bound, generics list bound and where clause.
|
||||
struct StructVariousBounds<T:Display>(T) where T:Debug;
|
@ -1,25 +0,0 @@
|
||||
[package]
|
||||
name = "shapely-macros"
|
||||
version = "0.1.0"
|
||||
authors = ["Enso Team <contact@luna-lang.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
macro-utils = { version = "0.1.0" , path = "../../macro-utils" }
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
Inflector = "0.11.4"
|
||||
itertools = "0.8.1"
|
||||
boolinator = "2.4.0"
|
||||
|
||||
[dependencies.syn]
|
||||
version = "1.0"
|
||||
features = [
|
||||
'extra-traits', 'visit', 'full'
|
||||
]
|
@ -1,224 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use macro_utils::field_names;
|
||||
use macro_utils::identifier_sequence;
|
||||
use macro_utils::index_sequence;
|
||||
use macro_utils::path_matching_ident;
|
||||
use syn::Attribute;
|
||||
use syn::DeriveInput;
|
||||
use syn::Data;
|
||||
use syn::DataEnum;
|
||||
use syn::DataStruct;
|
||||
use syn::Fields;
|
||||
use syn::Ident;
|
||||
use syn::Lit;
|
||||
use syn::Meta;
|
||||
use syn::MetaNameValue;
|
||||
use syn::NestedMeta;
|
||||
use syn::Variant;
|
||||
use syn::WhereClause;
|
||||
use syn::WherePredicate;
|
||||
|
||||
|
||||
|
||||
// ==============
|
||||
// === Consts ===
|
||||
// ==============
|
||||
|
||||
/// Name of the custom attribute allowing customizing behavior of the generated `CloneRef`
|
||||
/// implementation.
|
||||
const CLONE_REF_ATTR:&str = "clone_ref";
|
||||
|
||||
/// Name of the property within customization attribute that allows defining custom bounds for
|
||||
/// the generated `CloneRef` implementation.
|
||||
const BOUND_NAME:&str = "bound";
|
||||
|
||||
|
||||
|
||||
// ============================
|
||||
// === CloneRef for structs ===
|
||||
// ============================
|
||||
|
||||
/// `clone_ref` function body for a given `struct` definition.
|
||||
pub fn body_for_struct(ident:&Ident, data:&DataStruct) -> TokenStream {
|
||||
match data.fields {
|
||||
Fields::Unit =>
|
||||
// Foo
|
||||
quote!( #ident ),
|
||||
Fields::Unnamed(ref fields) => {
|
||||
let indices = index_sequence(fields.unnamed.len());
|
||||
// Foo(self.0.clone_ref())
|
||||
quote!(
|
||||
#ident(#(self.#indices.clone_ref()),*)
|
||||
)
|
||||
}
|
||||
Fields::Named(ref fields) => {
|
||||
let names = field_names(fields);
|
||||
// Foo { field0 : self.field0.clone_ref() }
|
||||
quote!(
|
||||
#ident {
|
||||
#(#names : self.#names.clone_ref()),*
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ==========================
|
||||
// === CloneRef for enums ===
|
||||
// ==========================
|
||||
|
||||
/// Prepares a match arm for a single variant that `clone_ref`s such value.
|
||||
pub fn arm_for_variant(data_ident:&Ident,variant:&Variant) -> TokenStream {
|
||||
let fields = &variant.fields;
|
||||
let variant_ident = &variant.ident;
|
||||
match fields {
|
||||
Fields::Unit => {
|
||||
// Enum::Var => Enum::Var
|
||||
quote!(
|
||||
#data_ident::#variant_ident => #data_ident::#variant_ident
|
||||
)
|
||||
}
|
||||
Fields::Named(fields) => {
|
||||
let names = field_names(fields);
|
||||
// Enum::Var {field0} => Enum::Var {field0 : field0.clone_ref()}
|
||||
quote!(
|
||||
#data_ident::#variant_ident { #(#names),* } =>
|
||||
#data_ident::#variant_ident {
|
||||
#( #names : #names.clone_ref() ),*
|
||||
}
|
||||
)
|
||||
}
|
||||
Fields::Unnamed(fields) => {
|
||||
let names = identifier_sequence(fields.unnamed.len());
|
||||
// Enum::Var(field0) => Enum::Var(field0.clone_ref())
|
||||
quote!(
|
||||
#data_ident::#variant_ident(#(#names),*) =>
|
||||
#data_ident::#variant_ident(
|
||||
#( #names.clone_ref() ),*
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `clone_ref` function body for a given `enum` definition.
|
||||
pub fn body_for_enum(ident:&Ident, data:&DataEnum) -> TokenStream {
|
||||
if data.variants.is_empty() {
|
||||
quote!(panic!("There cannot exist value of empty enum, so its clone_ref must not be called."))
|
||||
} else {
|
||||
let make_arm = |variant| arm_for_variant(ident,variant);
|
||||
let arms = data.variants.iter().map(make_arm);
|
||||
quote!(
|
||||
match self { #(#arms),* }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ============================
|
||||
// === Bounds customization ===
|
||||
// ============================
|
||||
|
||||
/// Checks if the given attribute is our customization attribute.
|
||||
pub fn is_clone_ref_customization(attr:&Attribute) -> bool {
|
||||
path_matching_ident(&attr.path,CLONE_REF_ATTR)
|
||||
}
|
||||
|
||||
/// Checks if the given Meta name-val pair defines user-provided bounds.
|
||||
pub fn is_custom_bound(name_val:&MetaNameValue) -> bool {
|
||||
path_matching_ident(&name_val.path,BOUND_NAME)
|
||||
}
|
||||
|
||||
/// If this is our customization attribute, we retrieve user-provided bounds for the generated
|
||||
/// `CloneRef` implementation.
|
||||
///
|
||||
/// Returns `None` is this is third-party attribute.
|
||||
/// Panics if this is our attribute but the syntax is not correct.
|
||||
pub fn clone_ref_bounds(attr:&Attribute) -> Option<Vec<WherePredicate>> {
|
||||
// Silently ignore foreign attributes. Be picky only about our one.
|
||||
is_clone_ref_customization(attr).then(())?;
|
||||
|
||||
let meta = attr.parse_meta().expect("Failed to parse attribute contents.");
|
||||
let list = match meta {
|
||||
Meta::List(ml) => ml.nested,
|
||||
_ => panic!("Attribute contents does not conform to meta item."),
|
||||
};
|
||||
if list.len() > 1 {
|
||||
panic!("Only a single entry within `{}` attribute is allowed.",CLONE_REF_ATTR);
|
||||
}
|
||||
let bound_value = match list.first() {
|
||||
Some(NestedMeta::Meta(Meta::NameValue(name_val))) => {
|
||||
if is_custom_bound(name_val) {
|
||||
&name_val.lit
|
||||
} else {
|
||||
panic!("`{}` attribute can define value only for `{}`.",CLONE_REF_ATTR,BOUND_NAME)
|
||||
}
|
||||
}
|
||||
Some(_) =>
|
||||
panic!("`{}` attribute must contain a single name=value assignment.",CLONE_REF_ATTR),
|
||||
None =>
|
||||
panic!("`{}` attribute must not be empty.",CLONE_REF_ATTR),
|
||||
};
|
||||
let bound_str = if let Lit::Str(lit_str) = bound_value {
|
||||
lit_str
|
||||
} else {
|
||||
panic!("`{}` value must be a string literal describing `where` predicates.",BOUND_NAME)
|
||||
};
|
||||
let bounds_text = format!("where {}", bound_str.value());
|
||||
let bounds = syn::parse_str::<WhereClause>(&bounds_text);
|
||||
let bounds = bounds.unwrap_or_else(|_| {
|
||||
panic!("Failed to parse user-provided where clause: `{}`.",bounds_text)
|
||||
});
|
||||
let ret = bounds.predicates.into_iter().collect();
|
||||
Some(ret)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===================
|
||||
// === Entry Point ===
|
||||
// ===================
|
||||
|
||||
/// Derives `CloneRef` implementation, refer to `crate::derive_clone_ref` for details.
|
||||
pub fn derive
|
||||
(input:proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let decl = syn::parse_macro_input!(input as DeriveInput);
|
||||
let ident = &decl.ident;
|
||||
let body = match &decl.data {
|
||||
Data::Struct(data_struct) => body_for_struct(ident,data_struct),
|
||||
Data::Enum(data_enum) => body_for_enum(ident,data_enum),
|
||||
Data::Union(_) =>
|
||||
panic!("CloneRef cannot be derived for an untagged union input."),
|
||||
};
|
||||
|
||||
let (impl_generics, ty_generics, inherent_where_clause_opt) = &decl.generics.split_for_impl();
|
||||
|
||||
// Where clause must contain both user-provided bounds and bounds inherent due to type
|
||||
// declaration-level where clause.
|
||||
let user_requested_bounds = decl.attrs.iter().filter_map(clone_ref_bounds).flatten();
|
||||
let mut where_clause = macro_utils::new_where_clause(user_requested_bounds);
|
||||
for inherent_where_clause in inherent_where_clause_opt {
|
||||
where_clause.predicates.extend(inherent_where_clause.predicates.iter().cloned())
|
||||
}
|
||||
|
||||
let output = quote!{
|
||||
impl #impl_generics CloneRef for #ident #ty_generics
|
||||
#where_clause {
|
||||
fn clone_ref(&self) -> Self {
|
||||
#body
|
||||
}
|
||||
}
|
||||
|
||||
impl #impl_generics From<& #ident #ty_generics> for #ident #ty_generics
|
||||
#where_clause {
|
||||
fn from(t:& #ident #ty_generics) -> Self {
|
||||
t.clone_ref()
|
||||
}
|
||||
}
|
||||
};
|
||||
output.into()
|
||||
}
|
@ -1,449 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use macro_utils::fields_list;
|
||||
use macro_utils::field_ident_token;
|
||||
use macro_utils::type_depends_on;
|
||||
use macro_utils::type_matches;
|
||||
use macro_utils::ty_path_type_args;
|
||||
use macro_utils::variant_depends_on;
|
||||
use boolinator::Boolinator;
|
||||
use inflector::Inflector;
|
||||
use itertools::Itertools;
|
||||
|
||||
|
||||
|
||||
// =============
|
||||
// === IsMut ===
|
||||
// =============
|
||||
|
||||
/// Describes whether a mutable or immutable iterator is being derived.
|
||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||
pub enum IsMut {
|
||||
Mutable,
|
||||
Immutable,
|
||||
}
|
||||
|
||||
impl IsMut {
|
||||
fn is_mut(self) -> bool {
|
||||
self == IsMut::Mutable
|
||||
}
|
||||
|
||||
/// Returns `mut` token for mutable iterator derivation.
|
||||
fn to_token(self) -> Option<syn::Token![mut]> {
|
||||
self.is_mut().as_some(<syn::Token![mut]>::default())
|
||||
}
|
||||
|
||||
/// Name of method for generating iterator.
|
||||
fn iter_method(self) -> TokenStream {
|
||||
if self.is_mut() {
|
||||
quote!(iter_mut)
|
||||
} else {
|
||||
quote!(iter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ======================
|
||||
// === DependentValue ===
|
||||
// ======================
|
||||
|
||||
/// A value dependent on out target parameter.
|
||||
///
|
||||
/// Helper methods can be used to generate code yielding values from this.
|
||||
pub struct DependentValue<'t> {
|
||||
/// Type of the value (ref-stripped).
|
||||
pub ty : &'t syn::Type,
|
||||
/// Tokens yielding the value.
|
||||
pub value : TokenStream,
|
||||
/// Parameter type we want to iterate over.
|
||||
pub target_param: &'t syn::GenericParam,
|
||||
/// Are the value yielded as reference.
|
||||
pub through_ref : bool
|
||||
}
|
||||
|
||||
impl<'t> DependentValue<'t> {
|
||||
/// Returns Some when type is dependent and None otherwise.
|
||||
pub fn try_new
|
||||
(ty: &'t syn::Type, value:TokenStream, target_param:&'t syn::GenericParam)
|
||||
-> Option<DependentValue<'t>> {
|
||||
if type_depends_on(ty, target_param) {
|
||||
Some(DependentValue{ty,value,target_param,through_ref:false})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects dependent sub-values from the tuple value.
|
||||
pub fn collect_tuple
|
||||
(tuple:&'t syn::TypeTuple, target_param:&'t syn::GenericParam)
|
||||
-> Vec<DependentValue<'t>> {
|
||||
tuple.elems.iter().enumerate().filter_map(|(ix,ty)| {
|
||||
let ix = syn::Index::from(ix);
|
||||
let ident = quote!(t.#ix);
|
||||
DependentValue::try_new(ty,ident,target_param)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
/// Generates code yielding all values of target type accessible from this
|
||||
/// value.
|
||||
pub fn yield_value(&self, is_mut:IsMut) -> TokenStream {
|
||||
match self.ty {
|
||||
syn::Type::Tuple(tuple) => self.yield_tuple_value(tuple, is_mut),
|
||||
syn::Type::Path(path) => {
|
||||
if type_matches(&self.ty, &self.target_param) {
|
||||
self.yield_direct_value(is_mut)
|
||||
} else {
|
||||
self.yield_dependent_ty_path_value(path,is_mut)
|
||||
}
|
||||
}
|
||||
_ =>
|
||||
panic!("Don't know how to yield value of type {} from type {}"
|
||||
, repr(&self.target_param), repr(&self.ty)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Code yielding value that directly matches the target parameter type.
|
||||
pub fn yield_direct_value
|
||||
(&self, is_mut:IsMut) -> TokenStream {
|
||||
let value = &self.value;
|
||||
let opt_mut = is_mut.to_token();
|
||||
let opt_ref = (!self.through_ref).as_some(quote!( & #opt_mut ));
|
||||
|
||||
// yield &mut value;
|
||||
quote!( yield #opt_ref #value; )
|
||||
}
|
||||
|
||||
/// Code yielding values from tuple dependent on the target parameter type.
|
||||
pub fn yield_tuple_value
|
||||
(&self, ty:&syn::TypeTuple,is_mut:IsMut)
|
||||
-> TokenStream {
|
||||
let value = &self.value;
|
||||
let mut_kwd = is_mut.to_token();
|
||||
let subfields = DependentValue::collect_tuple(ty, self.target_param);
|
||||
let yield_sub = subfields.iter().map(|f| {
|
||||
f.yield_value(is_mut)
|
||||
}).collect_vec();
|
||||
|
||||
// yield &mut t.0;
|
||||
// yield &mut t.2;
|
||||
quote!( {
|
||||
let t = & #mut_kwd #value;
|
||||
#(#yield_sub)*
|
||||
})
|
||||
}
|
||||
|
||||
/// Obtain the type of iterator-yielded value.
|
||||
///
|
||||
/// Panics when given a type which is not supported for derivation, like
|
||||
/// having dependent type on the non-last position.
|
||||
pub fn type_path_elem_type(&self, ty_path:&'t syn::TypePath) -> &syn::Type {
|
||||
let mut type_args = ty_path_type_args(ty_path);
|
||||
let last_arg = match type_args.pop() {
|
||||
Some(arg) => arg,
|
||||
None => panic!("Type {} has no segments!", repr(&ty_path))
|
||||
};
|
||||
|
||||
// Last and only last type argument is dependent.
|
||||
for non_last_segment in type_args {
|
||||
assert!(!type_depends_on(non_last_segment, self.target_param)
|
||||
, "Type {} has non-last argument {} that depends on {}"
|
||||
, repr(ty_path)
|
||||
, repr(non_last_segment)
|
||||
, repr(self.target_param)
|
||||
);
|
||||
}
|
||||
assert!(type_depends_on(last_arg, self.target_param));
|
||||
last_arg
|
||||
}
|
||||
|
||||
/// Code yielding values from data dependent on the target parameter type.
|
||||
pub fn yield_dependent_ty_path_value
|
||||
(&self, ty_path:&'t syn::TypePath, is_mut:IsMut)
|
||||
-> TokenStream {
|
||||
let opt_mut = is_mut.to_token();
|
||||
let elem_ty = self.type_path_elem_type(ty_path);
|
||||
let elem = quote!(t);
|
||||
|
||||
let elem_info = DependentValue{
|
||||
value : elem.clone(),
|
||||
target_param : self.target_param,
|
||||
ty : elem_ty,
|
||||
through_ref : true,
|
||||
};
|
||||
let yield_elem = elem_info.yield_value(is_mut);
|
||||
let value = &self.value;
|
||||
let iter_method = if is_mut.is_mut() {
|
||||
quote!(iter_mut)
|
||||
} else {
|
||||
quote!(iter)
|
||||
};
|
||||
|
||||
quote! {
|
||||
for #opt_mut #elem in #value.#iter_method() {
|
||||
#yield_elem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describe relevant fields of the struct definition.
|
||||
pub fn collect_struct
|
||||
(data:&'t syn::DataStruct, target_param:&'t syn::GenericParam)
|
||||
-> Vec<DependentValue<'t>> {
|
||||
let fields = fields_list(&data.fields);
|
||||
let dep_field = fields.iter().enumerate().filter_map(|(i,f)| {
|
||||
let ident = field_ident_token(f,i.into());
|
||||
let value = quote!(t.#ident);
|
||||
DependentValue::try_new(&f.ty,value,target_param)
|
||||
});
|
||||
dep_field.collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Parts of derivation output that are specific to enum- or struct- target.
|
||||
pub struct OutputParts<'ast> {
|
||||
pub iterator_tydefs : TokenStream,
|
||||
pub iter_body : TokenStream,
|
||||
pub iterator_params : Vec<&'ast syn::GenericParam>,
|
||||
}
|
||||
|
||||
/// Common data used when generating derived Iterator impls.
|
||||
///
|
||||
/// Examples are given for `pub struct Foo<S, T> { foo: T }`
|
||||
pub struct DerivingIterator<'ast> {
|
||||
pub data : &'ast syn::Data, // { foo: T }
|
||||
pub ident : &'ast syn::Ident, // Foo
|
||||
pub params : Vec<&'ast syn::GenericParam>, // <S, T>
|
||||
pub t_iterator : syn::Ident, // FooIterator{Mut}
|
||||
pub iterator : syn::Ident, // foo_iterator{_mut}
|
||||
pub target_param : &'ast syn::GenericParam, // T
|
||||
pub is_mut : IsMut, // are we mutable iterator?
|
||||
}
|
||||
|
||||
impl DerivingIterator<'_> {
|
||||
pub fn new<'ast>
|
||||
( decl :&'ast syn::DeriveInput
|
||||
, target_param:&'ast syn::GenericParam
|
||||
, is_mut :IsMut
|
||||
) -> DerivingIterator<'ast> {
|
||||
let mut_or_not = if is_mut.is_mut() { "Mut" } else { "" };
|
||||
let data = &decl.data;
|
||||
let params = decl.generics.params.iter().collect();
|
||||
let ident = &decl.ident;
|
||||
let t_iterator = format!("{}Iterator{}", ident, mut_or_not);
|
||||
let iterator = t_iterator.to_snake_case();
|
||||
let t_iterator = syn::Ident::new(&t_iterator, Span::call_site());
|
||||
let iterator = syn::Ident::new(&iterator , Span::call_site());
|
||||
DerivingIterator {
|
||||
data,
|
||||
ident,
|
||||
params,
|
||||
t_iterator,
|
||||
iterator,
|
||||
target_param,
|
||||
is_mut,
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles all enum-specific parts.
|
||||
pub fn prepare_parts_enum(&self, data:&syn::DataEnum) -> OutputParts {
|
||||
let opt_mut = &self.is_mut.to_token();
|
||||
let t_iterator = &self.t_iterator;
|
||||
let ident = &self.ident;
|
||||
let target_param = &self.target_param;
|
||||
let iterator_params = vec!(self.target_param);
|
||||
let iterator_tydefs = quote!(
|
||||
// type FooIterator<'t, U> =
|
||||
// Box<dyn Iterator<Item=&'t U> + 't>;
|
||||
// type FooIteratorMut<'t, U> =
|
||||
// Box<dyn Iterator<Item=&'t mut U> + 't>;
|
||||
type #t_iterator<'t, #(#iterator_params),*> =
|
||||
Box<dyn Iterator<Item=&'t #opt_mut #target_param> + 't>;
|
||||
);
|
||||
// For types that use target type parameter, refer to their
|
||||
// `IntoIterator` implementation. Otherwise, use `EmptyIterator`.
|
||||
let arms = data.variants.iter().map(|var| {
|
||||
let con = &var.ident;
|
||||
let iter = if variant_depends_on(var, target_param) {
|
||||
quote!(elem.into_iter())
|
||||
} else {
|
||||
quote!(shapely::EmptyIterator::new())
|
||||
};
|
||||
quote!(#ident::#con(elem) => Box::new(#iter))
|
||||
});
|
||||
|
||||
// match t {
|
||||
// Foo::Con1(elem) => Box::new(elem.into_iter()),
|
||||
// Foo::Con2(elem) => Box::new(shapely::EmptyIterator::new()),
|
||||
// }
|
||||
let iter_body = quote!( match t { #(#arms,)* } );
|
||||
OutputParts{iterator_tydefs,iter_body,iterator_params}
|
||||
}
|
||||
|
||||
/// Handles all struct-specific parts.
|
||||
pub fn prepare_parts_struct(&self, data:&syn::DataStruct) -> OutputParts {
|
||||
let opt_mut = &self.is_mut.to_token();
|
||||
let t_iterator = &self.t_iterator;
|
||||
let target_param = &self.target_param;
|
||||
let iterator_params = self.params.clone();
|
||||
let iterator_tydefs = quote!(
|
||||
// type FooIterator<'t, T> = impl Iterator<Item = &'t T>;
|
||||
// type FooIteratorMut<'t, T> = impl Iterator<Item = &'t mut T>;
|
||||
type #t_iterator<'t, #(#iterator_params),*> =
|
||||
impl Iterator<Item = &'t #opt_mut #target_param>;
|
||||
);
|
||||
let matched_fields = DependentValue::collect_struct(data, target_param);
|
||||
let yield_fields = matched_fields.iter().map(|field| {
|
||||
field.yield_value(self.is_mut)
|
||||
}).collect_vec();
|
||||
|
||||
// shapely::EmptyIterator::new()
|
||||
let empty_body = quote! { shapely::EmptyIterator::new() };
|
||||
|
||||
// shapely::GeneratingIterator(move || {
|
||||
// yield &t.foo;
|
||||
// })
|
||||
// shapely::GeneratingIterator(move || {
|
||||
// yield &mut t.foo;
|
||||
// })
|
||||
let body = quote! {
|
||||
shapely::GeneratingIterator
|
||||
(move || { #(#yield_fields)* })
|
||||
};
|
||||
|
||||
let iter_body = if matched_fields.is_empty() {
|
||||
empty_body
|
||||
} else {
|
||||
body
|
||||
};
|
||||
OutputParts{iterator_tydefs,iter_body,iterator_params}
|
||||
}
|
||||
|
||||
/// Handles common (between enum and struct) code and assembles it all
|
||||
/// into a final derivation output.
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn assemble_output(&self, parts:OutputParts) -> TokenStream {
|
||||
let iterator_tydefs = &parts.iterator_tydefs;
|
||||
let iter_body = &parts.iter_body;
|
||||
let iterator_params = &parts.iterator_params;
|
||||
let opt_mut = &self.is_mut.to_token();
|
||||
let iterator = &self.iterator;
|
||||
let t_iterator = &self.t_iterator;
|
||||
let params = &self.params;
|
||||
let ident = &self.ident;
|
||||
let target_param = &self.target_param;
|
||||
let iter_method = &self.is_mut.iter_method();
|
||||
|
||||
quote!{
|
||||
#iterator_tydefs
|
||||
|
||||
// pub fn foo_iterator<'t, T>
|
||||
// (t: &'t Foo<T>) -> FooIterator<'t, T> {
|
||||
// shapely::GeneratingIterator(move || {
|
||||
// yield &t.foo;
|
||||
// })
|
||||
// }
|
||||
// pub fn foo_iterator_mut<'t, T>
|
||||
// (t: &'t mut Foo<T>) -> FooIteratorMut<'t, T> {
|
||||
// shapely::GeneratingIterator(move || {
|
||||
// yield &t.foo;
|
||||
// })
|
||||
// }
|
||||
pub fn #iterator<'t, #(#params),*>
|
||||
(t: &'t #opt_mut #ident<#(#params),*>)
|
||||
-> #t_iterator<'t, #(#iterator_params),*> {
|
||||
#iter_body
|
||||
}
|
||||
|
||||
// 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, 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 #opt_mut #ident<#(#params),*> {
|
||||
type Item = &'t #opt_mut #target_param;
|
||||
type IntoIter = #t_iterator<'t, #(#iterator_params),*>;
|
||||
fn into_iter(self) -> #t_iterator<'t, #(#iterator_params),*> {
|
||||
#iterator(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),*> #ident<#(#params),*> {
|
||||
pub fn #iter_method
|
||||
(& #opt_mut self) -> #t_iterator<'_, #(#iterator_params),*> {
|
||||
#iterator(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates the code that derives desired iterator.
|
||||
pub fn output(&self) -> TokenStream {
|
||||
let parts = match self.data {
|
||||
syn::Data::Struct(data) => self.prepare_parts_struct(data),
|
||||
syn::Data::Enum (data) => self.prepare_parts_enum (data),
|
||||
_ =>
|
||||
panic!("Only Structs and Enums can derive(Iterator)!"),
|
||||
};
|
||||
self.assemble_output(parts)
|
||||
}
|
||||
}
|
||||
|
||||
/// Common implementation for deriving iterator through `derive(Iterator)` and
|
||||
/// `derive(IteratorMut)`.
|
||||
pub fn derive
|
||||
(input:proc_macro::TokenStream, is_mut:IsMut) -> proc_macro::TokenStream {
|
||||
let decl = syn::parse_macro_input!(input as syn::DeriveInput);
|
||||
let params = &decl.generics.params.iter().collect::<Vec<_>>();
|
||||
let output = match params.last() {
|
||||
Some(last_param) => {
|
||||
let der = DerivingIterator::new(&decl,last_param,is_mut);
|
||||
der.output()
|
||||
}
|
||||
None =>
|
||||
TokenStream::new(),
|
||||
};
|
||||
output.into()
|
||||
}
|
||||
|
||||
// Note [Expansion Example]
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// 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 }
|
||||
//
|
||||
// When different output is generated for mutable and immutable content, both
|
||||
// expansions are presented.
|
||||
//
|
||||
// For examples that are enum-specific rather than struct-specific, the
|
||||
// following definition is assumed:
|
||||
//
|
||||
// #[derive(Iterator)]
|
||||
// pub enum Foo<T> {
|
||||
// Con1(Bar<T>),
|
||||
// Con2(Baz),
|
||||
// }
|
||||
|
@ -1,98 +0,0 @@
|
||||
//! This crate defines a custom derive macro `Iterator`. Should not be used
|
||||
//! directly, but only through `shapely` crate, as it provides utilities
|
||||
//! necessary for the generated code to compile.
|
||||
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![warn(missing_docs)]
|
||||
#![warn(trivial_casts)]
|
||||
#![warn(trivial_numeric_casts)]
|
||||
#![warn(unused_import_braces)]
|
||||
#![warn(unused_qualifications)]
|
||||
#![warn(unsafe_code)]
|
||||
#![warn(missing_copy_implementations)]
|
||||
#![warn(missing_debug_implementations)]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
mod derive_clone_ref;
|
||||
mod derive_iterator;
|
||||
mod overlappable;
|
||||
|
||||
mod prelude {
|
||||
pub use macro_utils::repr;
|
||||
pub use proc_macro2::Span;
|
||||
pub use proc_macro2::TokenStream;
|
||||
pub use quote::quote;
|
||||
}
|
||||
|
||||
use crate::derive_iterator::IsMut;
|
||||
|
||||
/// For `struct Foo<T>` or `enum Foo<T>` provides:
|
||||
/// * `IntoIterator` implementations for `&'t Foo<T>`, `iter` and `into_iter`
|
||||
/// methods.
|
||||
///
|
||||
/// The iterators will:
|
||||
/// * for structs: go over each field that declared type is same as the
|
||||
/// struct's last type parameter.
|
||||
/// * enums: delegate to current constructor's nested value's iterator.
|
||||
///
|
||||
/// Enums are required to use only a single element tuple-like variant. This
|
||||
/// limitation should be lifted in the future.
|
||||
///
|
||||
/// Any dependent type stored in struct, tuple or wrapped in enum should have
|
||||
/// dependency only in its last type parameter. All dependent types that are not
|
||||
/// tuples nor directly the yielded type, are required to provide `iter` method
|
||||
/// that returns a compatible iterator (possible also derived).
|
||||
///
|
||||
/// Caller must have the following features enabled:
|
||||
/// ```
|
||||
/// #![feature(generators)]
|
||||
/// #![feature(type_alias_impl_trait)]
|
||||
/// ```
|
||||
///
|
||||
/// When used on type that takes no type parameters, like `struct Foo`, does
|
||||
/// nothing but yields no errors.
|
||||
#[proc_macro_derive(Iterator)]
|
||||
pub fn derive_iterator
|
||||
(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
derive_iterator::derive(input,IsMut::Immutable)
|
||||
}
|
||||
|
||||
/// Same as `derive(Iterator)` but generates mutable iterator.
|
||||
///
|
||||
/// It is separate, as some types allow deriving immutable iterator but ont the
|
||||
/// mutable one.
|
||||
#[proc_macro_derive(IteratorMut)]
|
||||
pub fn derive_iterator_mut
|
||||
(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
derive_iterator::derive(input,IsMut::Mutable)
|
||||
}
|
||||
|
||||
/// Derives `CloneRef` implementation for given type. It performs `clone_ref` on every member
|
||||
/// field. The input type must implement `Clone` and its every field must implement `CloneRef`.
|
||||
///
|
||||
/// For generic types no bounds are introduced in the generated implementation. To customize this
|
||||
/// behavior user might add `#[clone_ref(bound="…")]` attribute. Then the generated implementation
|
||||
/// will use the provided bounds.
|
||||
///
|
||||
/// Moreover, for a given struct `X` this macro generates also `impl From<&X> for X` which uses
|
||||
/// `CloneRef` under the hood. The semantics of `CloneRef` makes each object to naturally provide
|
||||
/// transformation from reference to an owned type.
|
||||
///
|
||||
/// Supported inputs are structs (unit, named, unnamed), enums (with unit, named, unnamed and no
|
||||
/// variants at all). Unions are currently not supported.
|
||||
#[proc_macro_derive(CloneRef, attributes(clone_ref))]
|
||||
pub fn derive_clone_ref
|
||||
(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
derive_clone_ref::derive(input)
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[proc_macro_attribute]
|
||||
pub fn overlappable
|
||||
( attrs : proc_macro::TokenStream
|
||||
, input : proc_macro::TokenStream
|
||||
) -> proc_macro::TokenStream {
|
||||
overlappable::overlappable(attrs,input)
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use proc_macro2::Ident;
|
||||
|
||||
pub fn overlappable
|
||||
( 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::ItemImpl);
|
||||
// let mut path = decl.trait_.unwrap().1.clone();
|
||||
// let path = path.segments.last_mut().iter().map(|ident| {
|
||||
// Ident::new(&format!("MarketCtx_{}", repr(ident)) , Span::call_site());
|
||||
// });
|
||||
|
||||
let mut marker_ctx_impl = decl;
|
||||
let mut trait_ = marker_ctx_impl.trait_.as_mut();
|
||||
trait_.iter_mut().for_each(|t| {
|
||||
let path = &mut t.1;
|
||||
path.segments.last_mut().iter_mut().for_each(|s| {
|
||||
let rr = repr(&s);
|
||||
s.ident = Ident::new(&format!("MarketCtx_{}", rr) , Span::call_site());
|
||||
});
|
||||
});
|
||||
|
||||
// let mut marker_ctx_impl = decl.clone();
|
||||
// let path = &mut marker_ctx_impl.trait_.as_mut().unwrap().1;
|
||||
// path.segments.last_mut().iter_mut().for_each(|s| {
|
||||
// let rr = repr(&s);
|
||||
// s.ident = Ident::new(&format!("MarketCtx_{}", rr) , Span::call_site());
|
||||
// });
|
||||
|
||||
// let name = repr(path);
|
||||
|
||||
// let marker_ctx_impl = syn::ItemImpl {
|
||||
// .. decl
|
||||
// };
|
||||
|
||||
|
||||
let _output_tmp = quote! {
|
||||
#marker_ctx_impl
|
||||
};
|
||||
let output = quote! {
|
||||
|
||||
};
|
||||
// println!("------------------");
|
||||
// println!("{}", output_tmp);
|
||||
output.into()
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ default = ["console_error_panic_hook"]
|
||||
|
||||
[dependencies]
|
||||
data = { version = "0.1.0" , path = "../../data" }
|
||||
enso-prelude = { version = "0.1.0" , path = "../../prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
logger = { version = "0.1.0" , path = "../../logger" }
|
||||
|
||||
console_error_panic_hook = { version = "0.1.1" , optional = true }
|
||||
|
@ -9,7 +9,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
web-test-proc-macro = { version = "0.1.0" , path = "../web-test-proc-macro" }
|
||||
ensogl = { version = "0.1.0" , path = "../../ensogl" }
|
||||
enso-prelude = { version = "0.1.0" , path = "../prelude" }
|
||||
enso-prelude = { version = "0.1.0" }
|
||||
ensogl-system-web = { version = "0.1.0" , path = "../system/web" }
|
||||
|
||||
wasm-bindgen = { version = "=0.2.58", features = ["nightly"] }
|
||||
|
Loading…
Reference in New Issue
Block a user