Refactor the crate structure (#967)

This commit is contained in:
Ara Adkins 2020-07-03 14:42:45 +01:00 committed by GitHub
parent 7c7352fa72
commit 919ffbdfac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
309 changed files with 7945 additions and 33 deletions

View File

@ -178,12 +178,4 @@ jobs:
# Tests
- name: Test WASM
shell: bash
run: |
cd parser
for dir in `ls`; do
cd $dir;
wasm-pack test --node;
cd ..;
done;
cd ..
run: ./tools/run --test-wasm

1
.gitignore vendored
View File

@ -53,6 +53,7 @@ cabal-dev
.vscode/
*.swp
.projections.json
.nvmrc
############################
## Rendered Documentation ##

View File

@ -1,7 +1,15 @@
[workspace]
members = [
"parser/flexer"
"lib/rust/enso-data",
"lib/rust/enso-generics",
"lib/rust/enso-logger",
"lib/rust/enso-macro-utils",
"lib/rust/enso-optics",
"lib/rust/enso-prelude",
"lib/rust/enso-shapely/impl",
"lib/rust/enso-shapely/macros",
"lib/rust/flexer",
]
[profile.dev]
@ -13,6 +21,7 @@ debug = true
opt-level = 3
lto = true
debug = false
panic = 'abort'
[profile.bench]
opt-level = 3

View File

@ -310,7 +310,7 @@ val typesafeConfigVersion = "1.4.0"
lazy val logger = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)
.crossType(CrossType.Pure)
.in(file("lib/logger"))
.in(file("lib/scala/logger"))
.settings(
version := "0.1",
libraryDependencies ++= scalaCompiler
@ -320,7 +320,7 @@ lazy val logger = crossProject(JVMPlatform, JSPlatform)
lazy val flexer = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)
.crossType(CrossType.Pure)
.in(file("lib/flexer"))
.in(file("lib/scala/flexer"))
.dependsOn(logger)
.settings(
version := "0.1",
@ -336,7 +336,7 @@ lazy val flexer = crossProject(JVMPlatform, JSPlatform)
lazy val `syntax-definition` = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)
.crossType(CrossType.Pure)
.in(file("lib/syntax/definition"))
.in(file("lib/scala/syntax/definition"))
.dependsOn(logger, flexer)
.settings(
scalacOptions ++= Seq("-Ypatmat-exhaust-depth", "off"),
@ -354,7 +354,7 @@ lazy val `syntax-definition` = crossProject(JVMPlatform, JSPlatform)
lazy val syntax = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)
.crossType(CrossType.Full)
.in(file("lib/syntax/specialization"))
.in(file("lib/scala/syntax/specialization"))
.dependsOn(logger, flexer, `syntax-definition`)
.configs(Test)
.configs(Benchmark)
@ -400,7 +400,7 @@ lazy val syntax = crossProject(JVMPlatform, JSPlatform)
Compile / fullOptJS / artifactPath := file("target/scala-parser.js")
)
lazy val `parser-service` = (project in file("lib/parser-service"))
lazy val `parser-service` = (project in file("lib/scala/parser-service"))
.dependsOn(syntax.jvm)
.settings(
libraryDependencies ++= akka,
@ -408,7 +408,7 @@ lazy val `parser-service` = (project in file("lib/parser-service"))
)
lazy val `text-buffer` = project
.in(file("lib/text-buffer"))
.in(file("lib/scala/text-buffer"))
.configs(Test)
.settings(
libraryDependencies ++= Seq(
@ -418,7 +418,7 @@ lazy val `text-buffer` = project
)
)
lazy val graph = (project in file("lib/graph/"))
lazy val graph = (project in file("lib/scala/graph/"))
.dependsOn(logger.jvm)
.configs(Test)
.settings(
@ -445,7 +445,7 @@ lazy val graph = (project in file("lib/graph/"))
scalacOptions ++= splainOptions
)
lazy val pkg = (project in file("lib/pkg"))
lazy val pkg = (project in file("lib/scala/pkg"))
.settings(
mainClass in (Compile, run) := Some("org.enso.pkg.Main"),
version := "0.1",
@ -455,7 +455,7 @@ lazy val pkg = (project in file("lib/pkg"))
)
)
lazy val `project-manager` = (project in file("lib/project-manager"))
lazy val `project-manager` = (project in file("lib/scala/project-manager"))
.settings(
(Compile / mainClass) := Some("org.enso.projectmanager.boot.ProjectManager")
)
@ -552,7 +552,7 @@ lazy val `project-manager` = (project in file("lib/project-manager"))
*/
lazy val `json-rpc-server` = project
.in(file("lib/json-rpc-server"))
.in(file("lib/scala/json-rpc-server"))
.settings(
libraryDependencies ++= akka,
libraryDependencies ++= circe,
@ -564,7 +564,7 @@ lazy val `json-rpc-server` = project
)
lazy val `json-rpc-server-test` = project
.in(file("lib/json-rpc-server-test"))
.in(file("lib/scala/json-rpc-server-test"))
.settings(
libraryDependencies ++= akka,
libraryDependencies ++= circe,
@ -576,7 +576,7 @@ lazy val `json-rpc-server-test` = project
)
.dependsOn(`json-rpc-server`)
lazy val `core-definition` = (project in file("lib/core-definition"))
lazy val `core-definition` = (project in file("lib/scala/core-definition"))
.configs(Benchmark)
.settings(
version := "0.1",
@ -605,7 +605,7 @@ lazy val `core-definition` = (project in file("lib/core-definition"))
.dependsOn(syntax.jvm)
lazy val searcher = project
.in(file("lib/searcher"))
.in(file("lib/scala/searcher"))
.configs(Test)
.settings(
libraryDependencies ++= akkaTest ++ Seq(
@ -616,6 +616,12 @@ lazy val searcher = project
)
.dependsOn(`json-rpc-server-test` % Test)
lazy val `interpreter-dsl` = (project in file("lib/scala/interpreter-dsl"))
.settings(
version := "0.1",
libraryDependencies += "com.google.auto.service" % "auto-service" % "1.0-rc7"
)
// ============================================================================
// === Sub-Projects ===========================================================
// ============================================================================
@ -901,8 +907,3 @@ lazy val runner = project
.dependsOn(`language-server`)
.dependsOn(`polyglot-api`)
lazy val `interpreter-dsl` = (project in file("lib/interpreter-dsl"))
.settings(
version := "0.1",
libraryDependencies += "com.google.auto.service" % "auto-service" % "1.0-rc7"
)

View File

@ -171,6 +171,11 @@ rustup override set nightly-2019-11-04
rustup component add clippy
```
You will also need `node` in order to run the `wasm` tests. We only support the
latest LTS version of [NodeJS](https://nodejs.org/en/download) and NPM. We
recommend using [`nvm`](https://github.com/nvm-sh/nvm) to manage node versions.
The current LTS is `v12.18.0`.
Please note that once the parser is integrated into the SBT build, the
rust-related commands will be automatically performed for you.
@ -236,6 +241,11 @@ a vanilla GraalVM distribution. To run it, use:
JAVA_HOME=<PATH_TO_GRAAL_HOME> ./enso.jar <CLI_ARGS>
```
#### Testing Enso
Running the tests for the JVM enso components is as simple as running
`sbt / test`. To test the Rust components you can run `cargo test`. Finally, you
can run the WASM tests for the rust components by using `./run --test-wasm`.
#### Installing the Jupyter kernel
Enso has a highly experimental and not-actively-maintained Jupyer Kernel.
To run it:

View File

@ -31,12 +31,14 @@ follows:
```rust
pub fn lexer_definition() -> String {
...
// ...
let chr = alphaNum | '_';
let blank = Pattern::from('_')
lexer.rule(lexer.root,blank,"self.on_ident(token::blank(self.start_location))");
// ...
}
```

View File

@ -0,0 +1,19 @@
[package]
name = "enso-data"
version = "0.1.0"
authors = ["Enso Team <enso-dev@enso.org>"]
edition = "2018"
description = "Useful data-types."
readme = "README.md"
homepage = "https://github.com/enso-org/enso/lib/rust/enso-data"
repository = "https://github.com/enso-org/enso"
license-file = "../../../LICENSE"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
enso-prelude = { version = "0.1.0" , path = "../enso-prelude" }
serde = { version = "1.0" , features = ["derive"] }

View File

@ -0,0 +1,2 @@
# Enso Data
Useful data types.

View File

@ -0,0 +1,331 @@
//! A tree structure build on top of the `HashMap`.
use crate::prelude::*;
use std::collections::hash_map::RandomState;
use std::hash::BuildHasher;
// ===================
// === HashMapTree ===
// ===================
/// A tree build on top of the `HashMap`. Each node in the tree can have zero or more branches
/// accessible by the given key type.
#[derive(Derivative)]
#[derivative(Debug (bound="K:Eq+Hash+Debug , V:Debug , S:BuildHasher"))]
#[derivative(Default (bound="K:Eq+Hash , V:Default , S:BuildHasher+Default"))]
#[derivative(Clone (bound="K:Clone , V:Clone , S:Clone"))]
pub struct HashMapTree<K,V,S=RandomState> {
/// Value of the current tree node.
pub value : V,
/// Branches of the current tree node.
pub branches : HashMap<K,HashMapTree<K,V,S>,S>
}
impl<K,T,S> HashMapTree<K,T,S>
where K : Eq+Hash,
S : BuildHasher+Default {
/// Constructor.
pub fn new() -> Self where T:Default {
default()
}
/// Constructor with explicit root value.
pub fn from_value(value:T) -> Self {
let branches = default();
Self {value,branches}
}
/// Sets the value at position described by `path`. In case a required sub-branch does not
/// exist, a default instance will be created.
#[inline]
pub fn set<P,I>(&mut self, path:P, value:T)
where P:IntoIterator<Item=I>, T:Default, I:Into<K> {
self.get_or_create_node(path).value = value;
}
/// Sets the value at position described by `path`. In case a required sub-branch does not
/// exist, uses `cons_missing` to create it.
#[inline]
pub fn set_with<P,I,F>(&mut self, path:P, value:T, cons_missing:F)
where P:IntoIterator<Item=I>, T:Default, I:Into<K>, F:FnMut()->T {
self.get_or_create_node_with(path,cons_missing).value = value;
}
/// Gets a reference to a value at the specified path if the path exists in the tree.
#[inline]
pub fn get<P,I>(&self, segments:P) -> Option<&T>
where P:IntoIterator<Item=I>, I:Into<K> {
self.get_node(segments).map(|node| &node.value)
}
/// Gets a mutable reference to a value at the specified path if the path exists in the tree.
#[inline]
pub fn get_mut<P,I>(&mut self, segments:P) -> Option<&mut T>
where P:IntoIterator<Item=I>, I:Into<K> {
self.get_node_mut(segments).map(|node| &mut node.value)
}
/// Gets a reference to a node at the specified path if the node exists.
#[inline]
pub fn get_node<P,I>(&self, segments:P) -> Option<&HashMapTree<K,T,S>>
where P:IntoIterator<Item=I>, I:Into<K> {
segments.into_iter().fold(Some(self),|map,t| {
map.and_then(|m| {
let key = t.into();
m.branches.get(&key)
})
})
}
/// Gets a mutable reference to a node at the specified path if the node exists.
#[inline]
pub fn get_node_mut<P,I>(&mut self, segments:P) -> Option<&mut HashMapTree<K,T,S>>
where P:IntoIterator<Item=I>, I:Into<K> {
segments.into_iter().fold(Some(self),|map,t| {
map.and_then(|m| {
let key = t.into();
m.branches.get_mut(&key)
})
})
}
/// Removes the node at the specified path.
#[inline]
pub fn remove<P,I>(&mut self, segments:P) -> Option<T>
where P:IntoIterator<Item=I>, I:Into<K> {
let mut segments = segments.into_iter().map(|t|t.into()).collect_vec();
segments.pop().and_then(|last| {
self.get_node_mut(segments).and_then(|node| {
node.branches.remove(&last).map(|branch| branch.value)
})
})
}
/// Iterates over keys in `path`. For each key, traverses into the appropriate branch. In case
/// the branch does not exist, a default instance will be created. Returns mutable reference to
/// the target tree node.
#[inline]
pub fn get_or_create_node<P,I>(&mut self, path:P) -> &mut HashMapTree<K,T,S>
where P:IntoIterator<Item=I>, T:Default, I:Into<K> {
self.get_or_create_node_with(path,default)
}
/// Iterates over keys in `path`. For each key, traverses into the appropriate branch. In case
/// the branch does not exist, uses `cons_missing` to construct it. Returns mutable reference to
/// the target tree node.
#[inline]
pub fn get_or_create_node_with<P,I,F>
(&mut self, path:P, cons_missing:F) -> &mut HashMapTree<K,T,S>
where P:IntoIterator<Item=I>, I:Into<K>, F:FnMut()->T {
self.get_or_create_node_traversing_with(path,cons_missing,|_|{})
}
/// Iterates over keys in `path`. For each key, traverses into the appropriate branch. In case
/// the branch does not exist, uses `cons_missing` provided with the current path to construct
/// it. Returns mutable reference to the target tree node.
#[inline]
pub fn get_or_create_node_path_with<P,I,F>
(&mut self, path:P, cons_missing:F) -> &mut HashMapTree<K,T,S>
where K:Clone, P:IntoIterator<Item=I>, I:Into<K>, F:FnMut(&[K])->T {
self.get_or_create_node_traversing_path_with(path,cons_missing,|_|{})
}
/// Iterates over keys in `path`. For each key, traverses into the appropriate branch. In case
/// the branch does not exist, uses `cons_missing` to construct it. Moreover, for each traversed
/// branch the `callback` is evaluated. Returns mutable reference to the target tree node.
#[inline]
pub fn get_or_create_node_traversing_with<P,I,F,M>
(&mut self, segments:P, mut cons_missing:F, mut callback:M) -> &mut HashMapTree<K,T,S>
where P:IntoIterator<Item=I>, I:Into<K>, F:FnMut()->T, M:FnMut(&mut HashMapTree<K,T,S>) {
segments.into_iter().fold(self,|map,t| {
let key = t.into();
let entry = map.branches.entry(key);
let node = entry.or_insert_with(|| HashMapTree::from_value(cons_missing()));
callback(node);
node
})
}
/// Iterates over keys in `path`. For each key, traverses into the appropriate branch. In case
/// the branch does not exist, uses `cons_missing` provided with the current path to construct
/// it. Moreover, for each traversed branch the `callback` is evaluated. Returns mutable
/// reference to the target tree node.
#[inline]
pub fn get_or_create_node_traversing_path_with<P,I,F,M>
(&mut self, segments:P, mut cons_missing:F, mut callback:M) -> &mut HashMapTree<K,T,S>
where K : Clone,
P : IntoIterator<Item=I>,
I : Into<K>,
F : FnMut(&[K])->T,
M : FnMut(&mut HashMapTree<K,T,S>) {
let mut path = Vec::new();
segments.into_iter().fold(self,|map,t| {
let key = t.into();
path.push(key.clone());
let entry = map.branches.entry(key);
let node = entry.or_insert_with(|| HashMapTree::from_value(cons_missing(&path)));
callback(node);
node
})
}
/// Zips two trees together into a new tree with cloned values.
#[inline]
pub fn zip_clone<T2>
(&self, other:&HashMapTree<K,T2,S>) -> HashMapTree<K,AtLeastOneOfTwo<T,T2>,S>
where K:Clone, T:Clone, T2:Clone {
Self::zip_clone_branches(Some(self),Some(other))
}
fn zip_clone_branches<T2>
(tree1:Option<&HashMapTree<K,T,S>>, tree2:Option<&HashMapTree<K,T2,S>>)
-> HashMapTree<K,AtLeastOneOfTwo<T,T2>,S>
where K:Clone, T:Clone, T2:Clone {
match (tree1,tree2) {
(Some(tree1),Some(tree2)) => {
let value = AtLeastOneOfTwo::Both(tree1.value.clone(),tree2.value.clone());
let mut keys = tree1.branches.keys().cloned().collect::<HashSet<K>>();
keys.extend(tree2.branches.keys().cloned());
let branches = keys.into_iter().map(|key| {
let branch1 = tree1.branches.get(&key);
let branch2 = tree2.branches.get(&key);
(key,Self::zip_clone_branches(branch1,branch2))
}).collect();
HashMapTree {value,branches}
}
(Some(tree),None) => {
let value = AtLeastOneOfTwo::First(tree.value.clone());
let mut keys = tree.branches.keys().cloned().collect::<HashSet<K>>();
keys.extend(tree.branches.keys().cloned());
let branches = tree.branches.iter().map(|(key,branch)| {
(key.clone(),Self::zip_clone_branches(Some(branch),None))
}).collect();
HashMapTree {value,branches}
}
(None,Some(tree)) => {
let value = AtLeastOneOfTwo::Second(tree.value.clone());
let mut keys = tree.branches.keys().cloned().collect::<HashSet<K>>();
keys.extend(tree.branches.keys().cloned());
let branches = tree.branches.iter().map(|(key,branch)| {
(key.clone(),Self::zip_clone_branches(None,Some(branch)))
}).collect();
HashMapTree {value,branches}
}
_ => panic!("Impossible")
}
}
}
impl<K,T,S> HashMapTree<K,Option<T>,S>
where K:Eq+Hash {
/// Gets the current value or creates new default one if missing.
pub fn value_or_default(&mut self) -> &mut T where T:Default {
self.value_or_set_with(default)
}
/// Gets the current value or creates new one if missing.
pub fn value_or_set(&mut self, val:T) -> &mut T {
self.value_or_set_with(move || val)
}
/// Gets the current value or creates new one if missing.
pub fn value_or_set_with<F>(&mut self, cons:F) -> &mut T
where F:FnOnce()->T {
if self.value.is_none() {
self.value = Some(cons());
};
self.value.as_mut().unwrap()
}
}
// === Impls ===
impl<K,V,S> PartialSemigroup<HashMapTree<K,V,S>> for HashMapTree<K,V,S>
where K : Eq + Hash + Clone,
V : Semigroup,
S : BuildHasher + Clone {
fn concat_mut(&mut self, other:Self) {
self.value.concat_mut(&other.value);
PartialSemigroup::concat_mut(&mut self.branches, other.branches);
}
}
impl<K,V,S> PartialSemigroup<&HashMapTree<K,V,S>> for HashMapTree<K,V,S>
where K : Eq + Hash + Clone,
V : Semigroup,
S : BuildHasher + Clone {
fn concat_mut(&mut self, other:&Self) {
self.value.concat_mut(&other.value);
PartialSemigroup::concat_mut(&mut self.branches, &other.branches);
}
}
// === Iterators ===
macro_rules! define_borrow_iterator {
($tp_name:ident $fn_name:ident $($mut:tt)?) => {
/// Iterator.
pub struct $tp_name<'a,K,V,S> {
iters : Vec<std::collections::hash_map::$tp_name<'a,K,HashMapTree<K,V,S>>>,
path : Vec<&'a K>,
}
impl<'a,K,V,S> Iterator for $tp_name<'a,K,V,S> {
type Item = (Vec<&'a K>, &'a $($mut)? V);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.iters.pop() {
None => break None,
Some(mut iter) => {
match iter.next() {
None => { self.path.pop(); }
Some((sub_key,sub_tree)) => {
self.iters.push(iter);
self.iters.push(sub_tree.branches.$fn_name());
self.path.push(sub_key);
break Some((self.path.clone(),& $($mut)? sub_tree.value))
}
}
}
}
}
}
}
impl<'a,K,V,S> IntoIterator for &'a $($mut)? HashMapTree<K,V,S> {
type Item = (Vec<&'a K>,&'a $($mut)? V);
type IntoIter = $tp_name<'a,K,V,S>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
let iters = vec![self.branches.$fn_name()];
let path = default();
$tp_name {iters,path}
}
}
impl<'a,K,V,S> Debug for $tp_name<'a,K,V,S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,stringify!($tp_name))
}
}
};
}
define_borrow_iterator!(Iter iter);
define_borrow_iterator!(IterMut iter_mut mut);
// =============
// === Tests ===
// =============
// TODO: We should have tests here.

View File

@ -0,0 +1,84 @@
//! This module defines a typed index struct. Useful to introduce type safety when using indexes
//! several indexable containers.
use crate::prelude::*;
// =============
// === Index ===
// =============
/// Typed newtype for `usize` meant to be used as a typed index.
pub struct Index<T> {
/// Raw value.
pub raw : usize,
phantom : PhantomData<T>
}
impl<T> Index<T> {
/// Constructor
pub fn new(raw:usize) -> Self {
let phantom = default();
Self {raw,phantom}
}
}
// === Impls ===
impl<T> Copy for Index<T> {}
impl<T> Eq for Index<T> {}
impl<T> Clone for Index<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Hash for Index<T> {
fn hash<H:std::hash::Hasher>(&self, state:&mut H) {
self.raw.hash(state)
}
}
impl<T> PartialEq for Index<T> {
fn eq(&self, other:&Self) -> bool {
self.raw == other.raw
}
}
impl<T> From<Index<T>> for usize {
fn from(t:Index<T>) -> Self {
t.raw
}
}
impl<T> From<&Index<T>> for usize {
fn from(t:&Index<T>) -> Self {
t.raw
}
}
impl<T> From<usize> for Index<T> {
fn from(t:usize) -> Self {
Self::new(t)
}
}
impl<T> From<&usize> for Index<T> {
fn from(t:&usize) -> Self {
Self::new(*t)
}
}
impl<T> Debug for Index<T> {
fn fmt(&self, f:&mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,"{}",self.raw)
}
}
impl<T> Display for Index<T> {
fn fmt(&self, f:&mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,"{}",self.raw)
}
}

View File

@ -0,0 +1,16 @@
//! Library of general data structures.
#![feature(associated_type_bounds)]
#![feature(trait_alias)]
#![warn(unsafe_code)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
pub mod hash_map_tree;
pub mod index;
pub mod opt_vec;
pub mod text;
pub use enso_prelude as prelude;

View File

@ -0,0 +1,259 @@
//! A sparse vector implementation.
use crate::prelude::*;
use std::iter::FilterMap;
use std::slice;
// ==============
// === OptVec ===
// ==============
// === Definition ===
/// A contiguous growable sparse array type. Similar to `Vec<T>`, but allowing missing values.
/// After a value is removed, it remembers the index for reuse in the future. Unlike `Vec`, it is
/// parametrized with optional `Index` type variable which will be used for indexing the vector.
/// Index have to implement the `Index` trait.
#[derive(Derivative)]
#[derivative(Default(bound=""))]
#[derive(Clone,Debug,Shrinkwrap)]
pub struct OptVec<T,Index=usize> {
#[shrinkwrap(main_field)]
items : Vec<Option<T>>,
free_ixs : SmallVec<[Index; 128]>,
}
// === Types ===
/// A trait for any vector index type.
pub trait Index = Debug + Copy + Into<usize> where usize : Into<Self>;
/// Iterator type of this vector.
pub type Iter<'t,T> = FilterMap<slice::Iter<'t,Option<T>>, OptionAsRef<T>>;
/// Mutable iterator type of this vector.
pub type IterMut<'t,T> = FilterMap<slice::IterMut<'t, Option<T>>, OptionAsRefMut<T>>;
/// Subtype of `Iter`.
pub type OptionAsRef <T> = for<'r> fn(&'r Option<T>) -> Option<&'r T>;
/// Subtype of `IterMut`.
pub type OptionAsRefMut <T> = for<'r> fn(&'r mut Option<T>) -> Option<&'r mut T>;
// === Construction ===
impl<T,I:Index> OptVec<T,I> {
/// Constructs a new, empty `Vec<T>`. It will not allocate until elements are pushed onto it.
pub fn new() -> Self {
default()
}
}
// === Status Checks ===
impl<T,I:Index> OptVec<T,I> {
/// Returns the number of elements in the vector, including reserved indexes. Also referred to
/// as its 'length'.
pub fn len(&self) -> usize {
self.items.len() - self.free_ixs.len()
}
/// Returns true if vector contains no element.
pub fn is_empty(&self) -> bool {
self.items.len() == self.free_ixs.len()
}
}
// === Modifiers ===
impl<T,I:Index> OptVec<T,I> {
/// Inserts the provided element to the vector. It reuses free indexes if any.
pub fn insert(&mut self, item: T) -> I {
self.insert_with_ix(|_| item)
}
/// Finds a free index and inserts the element. The index is re-used in case the array is sparse
/// or is added in case of no free places.
pub fn insert_with_ix<F:FnOnce(I) -> T>(&mut self, f: F) -> I {
match self.free_ixs.pop() {
None => {
let index = self.items.len().into();
self.items.push(Some(f(index)));
index
}
Some(index) => {
self.items[index.into()] = Some(f(index));
index
}
}
}
/// Reserve an index for further reuse. Please remember that you cannot use the index to read
/// values unless the value is set.
pub fn reserve_index(&mut self) -> I {
self.free_ixs.pop().unwrap_or_else(|| {
let index = self.items.len().into();
self.items.push(None);
index
})
}
/// Sets the value at given index. Panics if the index was already freed.
pub fn set(&mut self, index:I, t:T) {
self.items[index.into()] = Some(t);
}
/// Removes the element at provided index and marks the index to be reused. Does nothing if the
/// index was already empty. Panics if the index was out of bounds.
pub fn remove(&mut self, index:I) -> Option<T> {
let item = self.items[index.into()].take();
item.iter().for_each(|_| self.free_ixs.push(index));
item
}
}
// === Indexing ===
impl<T,I:Index> OptVec<T,I> {
/// Index into vector. Returns `None` if the key was already freed.
pub fn safe_index(&self, index:I) -> Option<&T> {
self.items[index.into()].as_ref()
}
/// Index into vector. Returns `None` if the key was already freed.
pub fn safe_index_mut(&mut self, index:I) -> Option<&mut T> {
self.items[index.into()].as_mut()
}
}
impl<T,I:Index> std::ops::Index<I> for OptVec<T,I> {
type Output = T;
fn index(&self, index:I) -> &Self::Output {
let error = || panic!(format!("Trying to access removed index `{:?}`.",index));
self.items.index(index.into()).as_ref().unwrap_or_else(error)
}
}
impl<T,I:Index> std::ops::IndexMut<I> for OptVec<T,I> {
fn index_mut(&mut self, index:I) -> &mut Self::Output {
let error = || panic!(format!("Trying to access removed index `{:?}`.",index));
self.items.index_mut(index.into()).as_mut().unwrap_or_else(error)
}
}
// === Iterators ===
impl<T,I:Index> OptVec<T,I> {
/// Iterator.
pub fn iter(&self) -> Iter<T> {
self.items.iter().filter_map(Option::as_ref)
}
/// Mutable iterator.
pub fn iter_mut(&mut self) -> IterMut<T> {
self.items.iter_mut().filter_map(Option::as_mut)
}
}
impl<'a,T,I:Index> IntoIterator for &'a OptVec<T,I> {
type Item = &'a T;
type IntoIter = Iter<'a,T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a,T,I:Index> IntoIterator for &'a mut OptVec<T,I> {
type Item = &'a mut T;
type IntoIter = IterMut<'a,T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
// =============
// === Tests ===
// =============
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
let mut v = OptVec::<usize>::new();
assert!(v.is_empty());
let ix1 = v.insert(1);
assert_eq!(ix1,0);
assert_eq!(v.len(),1);
assert!(!v.is_empty());
let ix2 = v.insert(2);
assert_eq!(ix2,1);
assert_eq!(v.len(),2);
v.remove(ix1);
assert_eq!(v.len(),1);
v.remove(ix2);
assert_eq!(v.len(),0);
assert!(v.is_empty());
let ix3 = v.insert(3);
assert_eq!(v.len(),1);
let ix4 = v.insert(4);
assert_eq!(ix3,1);
assert_eq!(ix4,0);
assert_eq!(v.len(),2);
}
#[test]
fn test_iter() {
let mut v = OptVec::<usize>::new();
let ix1 = v.insert(0);
let _ix2 = v.insert(1);
let _ix3 = v.insert(2);
assert_eq!(v.len(),3);
for (i,value) in v.into_iter().enumerate() {
assert_eq!(i, *value);
}
v.remove(ix1);
assert_eq!(v.len(),2);
for (i,value) in v.into_iter().enumerate() {
assert_eq!(i + 1, *value);
}
}
#[test]
fn test_iter_mut() {
let mut v = OptVec::<usize>::new();
let ix1 = v.insert(0);
let _ix2 = v.insert(1);
let _ix3 = v.insert(2);
assert_eq!(v.len(),3);
v.remove(ix1);
assert_eq!(v.len(),2);
for value in &mut v { *value *= 2; }
for (i, value) in v.into_iter().enumerate() {
assert_eq!((i + 1) * 2, *value);
}
}
}

View File

@ -0,0 +1,525 @@
//! The common structures for text location and manipulation.
use enso_prelude::*;
use std::ops::Add;
use std::ops::AddAssign;
use std::ops::Range;
use std::ops::Sub;
use std::ops::SubAssign;
use serde::Serialize;
use serde::Deserialize;
/// ======================================
/// === Text Coordinates And Distances ===
/// ======================================
// === Index ===
/// Strongly typed index into container.
#[allow(missing_docs)]
#[derive(Clone,Copy,Debug,Default,Hash,PartialEq,Eq,PartialOrd,Ord,Serialize,Deserialize)]
pub struct Index { pub value:usize }
impl Index {
/// Initializes Index with given value.
pub fn new(value:usize) -> Self {
Index {value}
}
/// Create char index from the byte index. It must traverse the content to count chars.
pub fn convert_byte_index(content:impl Str, index:ByteIndex) -> Self {
let slice = &content.as_ref()[..index.value];
Self::new(slice.chars().count())
}
}
// === ByteIndex ===
/// Strongly typed index of byte in String (which may differ with analogous character index,
/// because some chars takes more than one byte).
//TODO[ao] We should use structures from ensogl::,math::topology to represent different quantities
// and units.
#[allow(missing_docs)]
#[derive(Clone,Copy,Debug,Default,Hash,PartialEq,Eq,PartialOrd,Ord,Serialize,Deserialize)]
pub struct ByteIndex { pub value:usize }
impl ByteIndex {
/// Initializes Index with given value.
pub fn new(value:usize) -> Self {
ByteIndex {value}
}
}
// === Size ===
/// Strongly typed size of container.
#[allow(missing_docs)]
#[derive(Clone,Copy,Debug,Default,Hash,PartialEq,Eq,PartialOrd,Ord,Serialize,Deserialize)]
pub struct Size { pub value:usize }
impl Size {
/// Initializes Size with given value.
pub fn new(value:usize) -> Self {
Size {value}
}
/// Checks if this is a non-empty size (more than zero elements).
pub fn non_empty(self) -> bool {
self.value > 0
}
/// Checks if this is an empty size (zero elements).
pub fn is_empty(self) -> bool {
self.value == 0
}
}
impl Add for Size {
type Output = Size;
fn add(self, rhs:Size) -> Size {
Size {value:self.value + rhs.value}
}
}
impl AddAssign for Size {
fn add_assign(&mut self, rhs: Size) {
*self = *self + rhs;
}
}
impl Sub for Size {
type Output = Size;
fn sub(self, rhs:Size) -> Size {
Size{value: self.value - rhs.value}
}
}
impl SubAssign for Size {
fn sub_assign(&mut self, rhs: Size) {
*self = *self - rhs;
}
}
impl Display for Size {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,"{}",self.value)
}
}
impl From<&str> for Size {
fn from(text:&str) -> Self {
Size::new(text.len())
}
}
// === Span ===
/// Strongly typed span into container with index and size.
#[allow(missing_docs)]
#[derive(Clone,Copy,Debug,Default,Hash,PartialEq,Eq,PartialOrd,Ord,Serialize,Deserialize)]
pub struct Span { pub index:Index, pub size:Size }
impl Span {
/// Initializes Span with given values.
pub fn new(index:Index, size:Size) -> Self {
Span {index,size}
}
/// Creates a span describing a range between two indices.
pub fn from_indices(begin:Index, end:Index) -> Self {
if end < begin {
Self::from_indices(end,begin)
} else {
let index = begin;
let size = end - begin;
Span {index,size}
}
}
/// Creates a span from zero index with given length.
pub fn from_beginning(size:Size) -> Self {
Span {index:Index::new(0), size}
}
/// Get the character after last character of this span.
///
/// If span has size 0, it returns the `index` field.
pub fn end(&self) -> Index {
self.index + self.size
}
/// Check if this span contains character under `index`.
pub fn contains(&self, index:Index) -> bool {
self.index <= index && self.end() > index
}
/// Check if this span contains the whole another span.
pub fn contains_span(&self, span:&Span) -> bool {
self.index <= span.index && self.end() >= span.end()
}
/// Converts span to `Range<usize>`.
pub fn range(self) -> Range<usize> {
let start = self.index.value;
let end = self.end().value;
start .. end
}
/// Expand the span by moving its left (start) index.
pub fn extend_left(&mut self, size:Size) {
self.index -= size;
self.size += size;
}
/// Expand the span by moving its right (end) index.
pub fn extend_right(&mut self, size:Size) {
self.size += size;
}
/// Shrink the span by moving its left (start) index.
pub fn shrink_left(&mut self, size:Size) {
self.index += size;
self.size -= size;
}
/// Shrink the span by moving its right (end) index.
pub fn shrink_right(&mut self, size:Size) {
self.size -= size;
}
/// Move the whole span left, maintaining its size.
pub fn move_left(&mut self, size:Size) {
self.index -= size;
}
/// Move the whole span right, maintaining its size.
pub fn move_right(&mut self, size:Size) {
self.index += size;
}
/// Move the start index of the span, adjusting the size.
pub fn set_left(&mut self, new_left:Index) {
let end = self.end();
self.index = new_left;
self.size = end - new_left;
}
/// Move the end index of the span, adjusting the size.
pub fn set_right(&mut self, new_right:Index) {
self.size = new_right - self.index;
}
}
impls! { From + &From <Range<usize>> for Span { |range|
Span::from_indices(Index::new(range.start), Index::new(range.end))
}}
impls! { Into + &Into <Range<usize>> for Span { |this|
this.range()
}}
impl PartialEq<Range<usize>> for Span {
fn eq(&self, other:&Range<usize>) -> bool {
&self.range() == other
}
}
impl Display for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,"{}..{}",self.index.value,self.end().value)
}
}
impl std::ops::Index<Span> for str {
type Output = str;
fn index(&self, index:Span) -> &Self::Output {
&self[index.range()]
}
}
impl std::ops::Index<Span> for String {
type Output = str;
fn index(&self, index:Span) -> &Self::Output {
&self.as_str()[index]
}
}
impl From<Range<Index>> for Span {
fn from(range:Range<Index>) -> Self {
Span::from_indices(range.start,range.end)
}
}
// === Operators for Index and Size ===
impl Add<Size> for Index {
type Output = Index;
fn add(self, rhs:Size) -> Index {
Index {value:self.value + rhs.value}
}
}
impl AddAssign<Size> for Index {
fn add_assign(&mut self, rhs: Size) {
*self = *self + rhs;
}
}
impl Sub<Size> for Index {
type Output = Index;
fn sub(self, rhs:Size) -> Index {
Index {value:self.value - rhs.value}
}
}
impl SubAssign<Size> for Index {
fn sub_assign(&mut self, rhs: Size) {
*self = *self - rhs;
}
}
impl Sub for Index {
type Output = Size;
fn sub(self, rhs:Index) -> Size {
Size {value:self.value - rhs.value}
}
}
// === TextLocation ===
/// A position of character in a multiline text.
#[derive(Copy,Clone,Debug,PartialEq,Eq,PartialOrd,Ord)]
pub struct TextLocation {
/// Line index.
pub line: usize,
/// Column is a index of char in given line.
pub column: usize,
}
/// Short pretty print representation in the form of `line:column`.
impl Display for TextLocation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,"{}:{}",self.line,self.column)
}
}
impl TextLocation {
/// Create location at begin of given line.
pub fn at_line_begin(line_index:usize) -> Self {
TextLocation {
line : line_index,
column : 0,
}
}
/// Create location at begin of the whole document.
pub fn at_document_begin() -> Self {
TextLocation {
line : 0,
column : 0,
}
}
/// Create location at and of the whole document. It iterates over all the content.
pub fn at_document_end(content:impl Str) -> Self {
Self::after_chars(content.as_ref().chars())
}
/// Convert from index of document with `content`. It iterates over all characters before
/// `index`.
pub fn from_index(content:impl Str, index:Index) -> Self {
let before = content.as_ref().chars().take(index.value);
Self::after_chars(before)
}
/// Converts a range of indices into a range of TextLocation. It iterates over all characters
/// before range's end.
pub fn convert_range(content:impl Str, range:&Range<Index>) -> Range<Self> {
let content = content.as_ref();
Self::from_index(content,range.start)..Self::from_index(content,range.end)
}
/// Converts a range in bytes into a range of TextLocation. It iterates over all characters
/// before range's end.
pub fn convert_byte_range(content:impl Str, range:&Range<ByteIndex>) -> Range<Self> {
let start = Index::convert_byte_index(content.as_ref(), range.start);
let end = Index::convert_byte_index(content.as_ref(), range.end);
Self::convert_range(content,&(start..end))
}
fn after_chars<IntoCharsIter>(chars:IntoCharsIter) -> Self
where IntoCharsIter : IntoIterator<Item=char, IntoIter:Clone> {
let iter = chars.into_iter();
let len = iter.clone().count();
let newlines = iter.enumerate().filter(|(_,c)| *c == '\n');
let newlines_indices = newlines.map(|(i,_)| i);
TextLocation {
line : newlines_indices.clone().count(),
column : len - newlines_indices.last().map_or(0, |i| i + 1),
}
}
}
// ==============
// === Change ===
// ==============
/// A template for structure describing a text operation in one place.
///
/// This is a generalized template, because we use different representation for both index
/// (e.g. `Index` or `TextLocation`) and inserted content (it may be just String, but also e.g.
/// Vec<char>, or Vec<Vec<char>> split by newlines).
#[derive(Clone,Debug,Eq,Hash,PartialEq)]
pub struct TextChangeTemplate<Index,Content> {
/// Text fragment to be replaced. If we don't mean to remove any text, this should be an empty
/// range with start set at position there `lines` will be inserted
/// (see `TextChangeTemplate::insert` definition).
pub replaced: Range<Index>,
/// Text which replaces fragment described in `replaced` field.
pub inserted: Content,
}
/// The simplest change representation.
pub type TextChange = TextChangeTemplate<Index,String>;
// === Constructors ===
impl<Index:Copy,Content> TextChangeTemplate<Index,Content> {
/// Creates operation which inserts text at given position.
pub fn insert(at:Index, text:Content) -> Self {
TextChangeTemplate {
replaced : at..at,
inserted: text,
}
}
}
impl<Index,Content> TextChangeTemplate<Index,Content> {
/// Creates operation which replaces text at given range with given string.
pub fn replace(replaced:Range<Index>, text:Content) -> Self {
let inserted = text;
TextChangeTemplate {replaced,inserted}
}
}
impl<Index:Sub+Clone,Content> TextChangeTemplate<Index,Content> {
/// Calculate the size of the replaced text.
pub fn replaced_size(&self) -> Index::Output {
self.replaced.end.clone() - self.replaced.start.clone()
}
}
impl<Content> TextChangeTemplate<Index,Content> {
/// Calculate the size of the replaced text.
pub fn replaced_span(&self) -> Span {
let index = self.replaced.start;
let size = self.replaced_size();
Span {index,size}
}
/// Applies the text edit on given `String` value.
///
/// # Panics
///
/// Panics if the replaced span is out of the string value bounds.
pub fn apply(&self, target:&mut String) where Content:AsRef<str> {
//debug!(logger, "change: {change:?}, my code: \n```\n{code}\n```");
let replaced_indices = self.replaced.start.value..self.replaced.end.value;
//debug!(logger, "replacing range {replaced_indices:?} with {change.inserted}");
target.replace_range(replaced_indices,self.inserted.as_ref());
}
/// Applies the text edit on string and returns the result.
///
/// # Panics
///
/// Panics if the replaced span is out of the string value bounds.
pub fn applied(&self, target:&str) -> String where Content:AsRef<str> {
let mut target = target.to_string();
self.apply(&mut target);
target
}
}
impl<Index,Content:Default> TextChangeTemplate<Index,Content> {
/// Creates operation which deletes text at given range.
pub fn delete(range:Range<Index>) -> Self {
TextChangeTemplate {
replaced : range,
inserted : default(),
}
}
}
// =================
// === Utilities ===
// =================
/// Split text to lines handling both CR and CRLF line endings.
pub fn split_to_lines(text:&str) -> impl Iterator<Item=String> + '_ {
text.split('\n').map(cut_cr_at_end_of_line).map(|s| s.to_string())
}
/// Returns slice without carriage return (also known as CR or `'\r'`) at line's end
fn cut_cr_at_end_of_line(from:&str) -> &str {
if from.ends_with('\r') {
&from[..from.len()-1]
} else {
from
}
}
// ============
// === Text ===
// ============
#[cfg(test)]
mod test {
use super::*;
use super::Index;
#[test]
fn converting_index_to_location() {
let str = "first\nsecond\nthird";
assert_eq!(TextLocation::from_index(str,Index::new(0)), TextLocation {line:0, column:0});
assert_eq!(TextLocation::from_index(str,Index::new(5)), TextLocation {line:0, column:5});
assert_eq!(TextLocation::from_index(str,Index::new(6)), TextLocation {line:1, column:0});
assert_eq!(TextLocation::from_index(str,Index::new(9)), TextLocation {line:1, column:3});
assert_eq!(TextLocation::from_index(str,Index::new(12)), TextLocation {line:1, column:6});
assert_eq!(TextLocation::from_index(str,Index::new(13)), TextLocation {line:2, column:0});
assert_eq!(TextLocation::from_index(str,Index::new(18)), TextLocation {line:2, column:5});
let str = "";
assert_eq!(TextLocation {line:0, column:0}, TextLocation::from_index(str,Index::new(0)));
let str= "\n";
assert_eq!(TextLocation {line:0, column:0}, TextLocation::from_index(str,Index::new(0)));
assert_eq!(TextLocation {line:1, column:0}, TextLocation::from_index(str,Index::new(1)));
}
#[test]
fn text_location_at_end() {
let str = "first\nsecond\nthird";
assert_eq!(TextLocation::at_document_end(str) , TextLocation {line:2, column:5});
assert_eq!(TextLocation::at_document_end("") , TextLocation {line:0, column:0});
assert_eq!(TextLocation::at_document_end("\n"), TextLocation {line:1, column:0});
}
}

View File

@ -0,0 +1,19 @@
[package]
name = "enso-generics"
version = "0.1.0"
authors = ["Enso Team <enso-dev@enso.org>"]
edition = "2018"
description = "A library for type-level and generic programming."
readme = "README.md"
homepage = "https://github.com/enso-org/enso/lib/rust/enso-generics"
repository = "https://github.com/enso-org/enso"
license-file = "../../../LICENSE"
keywords = ["type-level", "generic"]
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
nalgebra = { version = "0.21.1" }

View File

@ -0,0 +1,2 @@
# Enso Generics
A library for generic and type-level programming.

View File

@ -0,0 +1,208 @@
//! Generic representation of data types. Refer to the crate documentation to learn more.
// This crate defines many helper traits and uses this flag on purpose.
#![allow(missing_docs)]
use super::hlist;
pub use nalgebra::base::dimension::*;
// ==============
// === Traits ===
// ==============
/// Common traits.
pub mod traits {
pub use super::HasRepr as _TRAIT_HasRepr;
pub use super::HasFieldsCount as _TRAIT_HasFieldsCount;
pub use super::HasItemAt as _TRAIT_HasItemAt;
pub use super::HasItemAt0 as _TRAIT_HasItemAt0;
pub use super::HasItemAt1 as _TRAIT_HasItemAt1;
pub use super::HasItemAt2 as _TRAIT_HasItemAt2;
pub use super::HasItemAt3 as _TRAIT_HasItemAt3;
pub use super::HasItemAt4 as _TRAIT_HasItemAt4;
pub use super::HasItemAt5 as _TRAIT_HasItemAt5;
pub use super::HasItemAt6 as _TRAIT_HasItemAt6;
pub use super::HasItemAt7 as _TRAIT_HasItemAt7;
pub use super::HasItemAt8 as _TRAIT_HasItemAt8;
pub use super::HasItemAt9 as _TRAIT_HasItemAt9;
pub use super::HasItemAt10 as _TRAIT_HasItemAt10;
pub use super::HasItemAt11 as _TRAIT_HasItemAt11;
pub use super::HasItemAt12 as _TRAIT_HasItemAt12;
pub use super::HasItemAt13 as _TRAIT_HasItemAt13;
pub use super::HasItemAt14 as _TRAIT_HasItemAt14;
pub use super::HasItemAt15 as _TRAIT_HasItemAt15;
pub use super::_GetItemAt as _TRAIT__GetItemAt;
pub use super::GetItemAt as _TRAIT_GetItemAt;
pub use super::GetItemAt0 as _TRAIT_GetItemAt0;
pub use super::GetItemAt1 as _TRAIT_GetItemAt1;
pub use super::GetItemAt2 as _TRAIT_GetItemAt2;
pub use super::GetItemAt3 as _TRAIT_GetItemAt3;
pub use super::GetItemAt4 as _TRAIT_GetItemAt4;
pub use super::GetItemAt5 as _TRAIT_GetItemAt5;
pub use super::GetItemAt6 as _TRAIT_GetItemAt6;
pub use super::GetItemAt7 as _TRAIT_GetItemAt7;
pub use super::GetItemAt8 as _TRAIT_GetItemAt8;
pub use super::GetItemAt9 as _TRAIT_GetItemAt9;
pub use super::GetItemAt10 as _TRAIT_GetItemAt10;
pub use super::GetItemAt11 as _TRAIT_GetItemAt11;
pub use super::GetItemAt12 as _TRAIT_GetItemAt12;
pub use super::GetItemAt13 as _TRAIT_GetItemAt13;
pub use super::GetItemAt14 as _TRAIT_GetItemAt14;
pub use super::GetItemAt15 as _TRAIT_GetItemAt15;
pub use super::ItemAt as _TRAIT_ItemAt;
pub use super::ItemAt0 as _TRAIT_ItemAt0;
pub use super::ItemAt1 as _TRAIT_ItemAt1;
pub use super::ItemAt2 as _TRAIT_ItemAt2;
pub use super::ItemAt3 as _TRAIT_ItemAt3;
pub use super::ItemAt4 as _TRAIT_ItemAt4;
pub use super::ItemAt5 as _TRAIT_ItemAt5;
pub use super::ItemAt6 as _TRAIT_ItemAt6;
pub use super::ItemAt7 as _TRAIT_ItemAt7;
pub use super::ItemAt8 as _TRAIT_ItemAt8;
pub use super::ItemAt9 as _TRAIT_ItemAt9;
pub use super::ItemAt10 as _TRAIT_ItemAt10;
pub use super::ItemAt11 as _TRAIT_ItemAt11;
pub use super::ItemAt12 as _TRAIT_ItemAt12;
pub use super::ItemAt13 as _TRAIT_ItemAt13;
pub use super::ItemAt14 as _TRAIT_ItemAt14;
pub use super::ItemAt15 as _TRAIT_ItemAt15;
}
// ===============
// === HasRepr ===
// ===============
/// Association of a given type with its generic representation.
pub trait HasRepr {
type GenericRepr : hlist::HList;
}
/// Type level accessor of a generic representation of the given type.
pub type Repr<T> = <T as HasRepr>::GenericRepr;
/// Converts the type to its generic representation. Please note that this trait is implemented
/// automatically for every type which implements `Into<Repr<Self>>`.
pub trait IntoGeneric : HasRepr + Into<Repr<Self>> {
fn into_generic(self) -> Repr<Self> {
self.into()
}
}
impl<T> IntoGeneric for T where T : HasRepr + Into<Repr<T>> {}
// ======================
// === HasFieldsCount ===
// ======================
/// Information of field count of any structure implementing `Generics`. This trait is implemented
/// automatically.
pub trait HasFieldsCount {
const FIELDS_COUNT : usize;
fn fields_count() -> usize {
Self::FIELDS_COUNT
}
}
impl<T> HasFieldsCount for T
where T:HasRepr {
const FIELDS_COUNT : usize = <Repr<T> as hlist::HasLength>::LEN;
}
// ================
// === HasIndex ===
// ================
/// Trait for heterogeneous containers like tuples which contain element at index `Ix`.
pub trait HasItemAt<Ix> { type Item; }
pub trait HasItemAt0 = HasItemAt<U0>;
pub trait HasItemAt1 = HasItemAt<U1>;
pub trait HasItemAt2 = HasItemAt<U2>;
pub trait HasItemAt3 = HasItemAt<U3>;
pub trait HasItemAt4 = HasItemAt<U4>;
pub trait HasItemAt5 = HasItemAt<U5>;
pub trait HasItemAt6 = HasItemAt<U6>;
pub trait HasItemAt7 = HasItemAt<U7>;
pub trait HasItemAt8 = HasItemAt<U8>;
pub trait HasItemAt9 = HasItemAt<U9>;
pub trait HasItemAt10 = HasItemAt<U10>;
pub trait HasItemAt11 = HasItemAt<U11>;
pub trait HasItemAt12 = HasItemAt<U12>;
pub trait HasItemAt13 = HasItemAt<U13>;
pub trait HasItemAt14 = HasItemAt<U14>;
pub trait HasItemAt15 = HasItemAt<U15>;
/// Type of element at index `Ix`. Useful for heterogeneous containers like tuples.
pub type ItemAt<Ix,T> = <T as HasItemAt<Ix>>::Item;
pub type ItemAt0 <T> = ItemAt <U0 , T>;
pub type ItemAt1 <T> = ItemAt <U1 , T>;
pub type ItemAt2 <T> = ItemAt <U2 , T>;
pub type ItemAt3 <T> = ItemAt <U3 , T>;
pub type ItemAt4 <T> = ItemAt <U4 , T>;
pub type ItemAt5 <T> = ItemAt <U5 , T>;
pub type ItemAt6 <T> = ItemAt <U6 , T>;
pub type ItemAt7 <T> = ItemAt <U7 , T>;
pub type ItemAt8 <T> = ItemAt <U8 , T>;
pub type ItemAt9 <T> = ItemAt <U9 , T>;
pub type ItemAt10 <T> = ItemAt <U10 , T>;
pub type ItemAt11 <T> = ItemAt <U11 , T>;
pub type ItemAt12 <T> = ItemAt <U12 , T>;
pub type ItemAt13 <T> = ItemAt <U13 , T>;
pub type ItemAt14 <T> = ItemAt <U14 , T>;
pub type ItemAt15 <T> = ItemAt <U15 , T>;
/// Accessor for element at index `Ix`.
pub trait GetItemAt<Ix> : HasItemAt<Ix> + _GetItemAt {
fn get_item_at(&self) -> &ItemAt<Ix,Self>;
}
/// Smart wrapper for `GetItemAt`. Enables syntax `lst.item_at::<U0>()`.
impl<T> _GetItemAt for T {}
pub trait _GetItemAt {
fn item_at<Ix>(&self) -> &ItemAt<Ix,Self> where Self:GetItemAt<Ix> {
GetItemAt::<Ix>::get_item_at(self)
}
}
pub trait GetItemAt0 : GetItemAt <U0> { fn _0(&self) -> &ItemAt0 <Self> {self.item_at::<U0> ()} }
pub trait GetItemAt1 : GetItemAt <U1> { fn _1(&self) -> &ItemAt1 <Self> {self.item_at::<U1> ()} }
pub trait GetItemAt2 : GetItemAt <U2> { fn _2(&self) -> &ItemAt2 <Self> {self.item_at::<U2> ()} }
pub trait GetItemAt3 : GetItemAt <U3> { fn _3(&self) -> &ItemAt3 <Self> {self.item_at::<U3> ()} }
pub trait GetItemAt4 : GetItemAt <U4> { fn _4(&self) -> &ItemAt4 <Self> {self.item_at::<U4> ()} }
pub trait GetItemAt5 : GetItemAt <U5> { fn _5(&self) -> &ItemAt5 <Self> {self.item_at::<U5> ()} }
pub trait GetItemAt6 : GetItemAt <U6> { fn _6(&self) -> &ItemAt6 <Self> {self.item_at::<U6> ()} }
pub trait GetItemAt7 : GetItemAt <U7> { fn _7(&self) -> &ItemAt7 <Self> {self.item_at::<U7> ()} }
pub trait GetItemAt8 : GetItemAt <U8> { fn _8(&self) -> &ItemAt8 <Self> {self.item_at::<U8> ()} }
pub trait GetItemAt9 : GetItemAt <U9> { fn _9(&self) -> &ItemAt9 <Self> {self.item_at::<U9> ()} }
pub trait GetItemAt10 : GetItemAt<U10> { fn _10(&self) -> &ItemAt10 <Self> {self.item_at::<U10>()} }
pub trait GetItemAt11 : GetItemAt<U11> { fn _11(&self) -> &ItemAt11 <Self> {self.item_at::<U11>()} }
pub trait GetItemAt12 : GetItemAt<U12> { fn _12(&self) -> &ItemAt12 <Self> {self.item_at::<U12>()} }
pub trait GetItemAt13 : GetItemAt<U13> { fn _13(&self) -> &ItemAt13 <Self> {self.item_at::<U13>()} }
pub trait GetItemAt14 : GetItemAt<U14> { fn _14(&self) -> &ItemAt14 <Self> {self.item_at::<U14>()} }
pub trait GetItemAt15 : GetItemAt<U15> { fn _15(&self) -> &ItemAt15 <Self> {self.item_at::<U15>()} }
impl<T:GetItemAt<U0>> GetItemAt0 for T {}
impl<T:GetItemAt<U1>> GetItemAt1 for T {}
impl<T:GetItemAt<U2>> GetItemAt2 for T {}
impl<T:GetItemAt<U3>> GetItemAt3 for T {}
impl<T:GetItemAt<U4>> GetItemAt4 for T {}
impl<T:GetItemAt<U5>> GetItemAt5 for T {}
impl<T:GetItemAt<U6>> GetItemAt6 for T {}
impl<T:GetItemAt<U7>> GetItemAt7 for T {}
impl<T:GetItemAt<U8>> GetItemAt8 for T {}
impl<T:GetItemAt<U9>> GetItemAt9 for T {}
impl<T:GetItemAt<U10>> GetItemAt10 for T {}
impl<T:GetItemAt<U11>> GetItemAt11 for T {}
impl<T:GetItemAt<U12>> GetItemAt12 for T {}
impl<T:GetItemAt<U13>> GetItemAt13 for T {}
impl<T:GetItemAt<U14>> GetItemAt14 for T {}
impl<T:GetItemAt<U15>> GetItemAt15 for T {}

View File

@ -0,0 +1,369 @@
//! HList provides many operations to create and manipulate heterogenous lists (HLists) whose length
//! and element types are known at compile-time. HLists can be used to implement records, variants,
//! type-indexed products (TIP), type-indexed co-products (TIC), or keyword arguments.
// =============
// === HList ===
// =============
/// Type of every `HList`.
pub trait HList = HasLength;
/// Empty `HList` value.
#[derive(Debug,Clone,Copy)]
pub struct Nil;
/// Non-empty `HList` with head and tail.
#[derive(Debug,Clone,Copy)]
#[allow(missing_docs)]
pub struct Cons<Head,Tail>(pub Head, pub Tail);
// === Smart Constructors ===
/// Creates new `HList` from the provided elements, similar to `vec!`. In order to provide type for
/// the list, use the `ty` macro. In order to pattern match on it, use the `pat` macro.
///
/// ```compile_fail
/// let HList::pat![t1,t2] : HList::ty![&str,usize] = HList::new!["hello",7];
/// ```
#[macro_export]
macro_rules! new {
($(,)*) => { $crate::Nil };
($t:expr $(,$($ts:expr),*)?) => {
$crate::Cons($t,$crate::new!{$($($ts),*)?})
}
}
/// Pattern matches on a `HList`. See docs of `new` to learn more.
#[macro_export]
macro_rules! pat {
($(,)*) => { $crate::Nil };
($t:pat $(,$($ts:pat),*)?) => {
$crate::Cons($t,$crate::pat!{$($($ts),*)?})
}
}
/// Smart `HList` type constructor. See docs of `new` to learn more.
#[macro_export]
macro_rules! ty {
($(,)*) => { $crate::Nil };
($t:ty $(,$($ts:ty),*)?) => {
$crate::Cons<$t,$crate::ty!{$($($ts),*)?}>
}
}
// ==============
// === Length ===
// ==============
/// Compile-time known length value.
#[allow(missing_docs)]
pub trait HasLength {
const LEN : usize;
fn len() -> usize {
Self::LEN
}
}
/// Compile-time known length value.
pub const fn len<T:HasLength>() -> usize {
<T as HasLength>::LEN
}
impl HasLength for Nil { const LEN : usize = 0; }
impl<H,T:HasLength> HasLength for Cons<H,T> { const LEN : usize = 1 + len::<T>(); }
// ============
// === Head ===
// ============
/// Head element accessor.
#[allow(missing_docs)]
pub trait KnownHead {
type Head;
}
/// Head element type accessor.
pub type Head<T> = <T as KnownHead>::Head;
/// Head element accessor.
#[allow(missing_docs)]
pub trait GetHead : KnownHead {
fn head(&self) -> &Self::Head;
}
/// Mutable head element accessor.
#[allow(missing_docs)]
pub trait GetHeadMut : KnownHead {
fn head_mut(&mut self) -> &mut Self::Head;
}
/// Head element clone.
#[allow(missing_docs)]
pub trait GetHeadClone : KnownHead {
fn head_clone(&self) -> Self::Head;
}
impl<T> GetHeadClone for T
where T:GetHead, Head<T>:Clone {
default fn head_clone(&self) -> Self::Head {
self.head().clone()
}
}
// === Impls ===
impl<H,T> KnownHead for Cons<H,T> {
type Head = H;
}
impl<H,T> GetHead for Cons<H,T> {
fn head(&self) -> &Self::Head {
&self.0
}
}
impl<H,T> GetHeadMut for Cons<H,T> {
fn head_mut(&mut self) -> &mut Self::Head {
&mut self.0
}
}
// ============
// === Tail ===
// ============
/// Tail element accessor.
#[allow(missing_docs)]
pub trait KnownTail {
type Tail;
}
/// Tail element type accessor.
pub type Tail<T> = <T as KnownTail>::Tail;
/// Tail element accessor.
#[allow(missing_docs)]
pub trait GetTail : KnownTail {
fn tail(&self) -> &Self::Tail;
}
/// Mutable tail element accessor.
#[allow(missing_docs)]
pub trait GetTailMut : KnownTail {
fn tail_mut(&mut self) -> &mut Self::Tail;
}
/// Tail element clone.
#[allow(missing_docs)]
pub trait GetTailClone : KnownTail {
fn tail_clone(&self) -> Self::Tail;
}
impl<T> GetTailClone for T
where T:GetTail, Tail<T>:Clone {
default fn tail_clone(&self) -> Self::Tail {
self.tail().clone()
}
}
// === Impls ===
impl<H,T> KnownTail for Cons<H,T> {
type Tail = T;
}
impl<H,T> GetTail for Cons<H,T> {
fn tail(&self) -> &Self::Tail {
&self.1
}
}
impl<H,T> GetTailMut for Cons<H,T> {
fn tail_mut(&mut self) -> &mut Self::Tail {
&mut self.1
}
}
// ============
// === Last ===
// ============
/// Last element accessor.
#[allow(missing_docs)]
pub trait KnownLast {
type Last;
}
/// Last element type accessor.
pub type Last<T> = <T as KnownLast>::Last;
/// Last element accessor.
#[allow(missing_docs)]
pub trait GetLast : KnownLast {
fn last(&self) -> &Self::Last;
}
/// Mutable last element accessor.
#[allow(missing_docs)]
pub trait GetLastMut : KnownLast {
fn last_mut(&mut self) -> &mut Self::Last;
}
/// Last element clone.
#[allow(missing_docs)]
pub trait GetLastClone : KnownLast {
fn last_clone(&self) -> Self::Last;
}
impl<T> GetLastClone for T
where T:GetLast, Last<T>:Clone {
default fn last_clone(&self) -> Self::Last {
self.last().clone()
}
}
// === Impls ===
impl<H> KnownLast for Cons<H,Nil> { type Last = H; }
impl<H,T:KnownLast> KnownLast for Cons<H,T> { type Last = Last<T>; }
impl<H> GetLast for Cons<H,Nil> {
fn last(&self) -> &Self::Last {
&self.0
}
}
impl<H> GetLastMut for Cons<H,Nil> {
fn last_mut(&mut self) -> &mut Self::Last {
&mut self.0
}
}
impl<H,T:GetLast> GetLast for Cons<H,T> {
fn last(&self) -> &Self::Last {
self.tail().last()
}
}
impl<H,T:GetLastMut> GetLastMut for Cons<H,T> {
fn last_mut(&mut self) -> &mut Self::Last {
self.tail_mut().last_mut()
}
}
// ============
// === Init ===
// ============
/// Init elements accessor (all but last).
#[allow(missing_docs)]
pub trait KnownInit {
type Init;
}
/// Init elements type accessor.
pub type Init<T> = <T as KnownInit>::Init;
/// Init element clone.
#[allow(missing_docs)]
pub trait GetInitClone : KnownInit {
fn init_clone(&self) -> Self::Init;
}
// === Impls ===
impl<H> KnownInit for Cons<H,Nil> { type Init = Nil; }
impl<H,T:KnownInit> KnownInit for Cons<H,T> { type Init = Cons<H,Init<T>>; }
impl<H> GetInitClone for Cons<H,Nil> {
fn init_clone(&self) -> Self::Init {
Nil
}
}
impl<H:Clone,T:GetInitClone> GetInitClone for Cons<H,T> {
fn init_clone(&self) -> Self::Init {
Cons(self.head().clone(),self.tail().init_clone())
}
}
// ================
// === PushBack ===
// ================
// TODO: Consider implementing PushBack for everything that converts to and from HList.
/// Add a new element to the back of the list.
#[allow(missing_docs)]
pub trait PushBack<T> : Sized {
type Output : KnownLast<Last=T> + KnownInit<Init=Self>;
fn push_back(self,t:T) -> Self::Output;
}
impl<X> PushBack<X> for Nil {
type Output = Cons<X,Nil>;
#[inline(always)]
fn push_back(self,x:X) -> Self::Output {
Cons(x,Nil)
}
}
impl<X,H,T> PushBack<X> for Cons<H,T>
where T:PushBack<X> {
type Output = Cons<H,<T as PushBack<X>>::Output>;
#[inline(always)]
fn push_back(self,x:X) -> Self::Output {
let Cons(head,tail) = self;
Cons(head,tail.push_back(x))
}
}
// ===============
// === PopBack ===
// ===============
// TODO: Consider implementing PopBack for everything that converts to and from HList.
/// Remove the last element of the list and return it and the new list.
#[allow(missing_docs)]
pub trait PopBack : KnownLast + KnownInit {
fn pop_back(self) -> (Self::Last,Self::Init);
}
impl<H> PopBack for Cons<H,Nil> {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.0,Nil)
}
}
impl<H,T> PopBack for Cons<H,T>
where T:PopBack {
fn pop_back(self) -> (Self::Last,Self::Init) {
let (last,tail) = self.1.pop_back();
(last,Cons(self.0,tail))
}
}

View File

@ -0,0 +1,30 @@
//! Rust Generics implementation.
//!
//! Datatype-generic programming, also frequently just called generic programming or generics, is a
//! form of abstraction that allows defining functions that can operate on a large class of
//! data types. For a more in-depth introduction to generic programming in general, have a look at
//! [Datatype-Generic Programming](http://www.cs.ox.ac.uk/jeremy.gibbons/publications/dgp.pdf), or
//! the [Libraries for Generic Programming](http://dreixel.net/research/pdf/lgph.pdf) paper.
#![deny(unconditional_recursion)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unsafe_code)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![feature(const_fn)]
#![feature(specialization)]
#![feature(trait_alias)]
pub mod generic;
pub mod hlist;
pub mod tuple;
pub use generic::*;
pub use hlist::*;
pub use tuple::*;

View File

@ -0,0 +1,622 @@
//! This module contains implementations of generic operations on tuples.
use crate as hlist;
use nalgebra::base::dimension::*;
// ====================
// === HasTupleRepr ===
// ====================
/// All types which have a tuple representation.
#[allow(missing_docs)]
pub trait HasTupleRepr {
type TupleRepr;
}
/// Tuple representation of a type.
pub type TupleRepr<T> = <T as HasTupleRepr>::TupleRepr;
/// Conversion of the given type to its tuple representation.
#[allow(missing_docs)]
pub trait IntoTuple : HasTupleRepr + Into<TupleRepr<Self>> {
fn into_tuple(self) -> TupleRepr<Self> {
self.into()
}
}
impl<T> IntoTuple for T where T : HasTupleRepr + Into<TupleRepr<T>> {}
// ===================
// === GenericRepr ===
// ===================
macro_rules! gen_as_hlist_for_tuples {
() => {};
($t:ident $(,$($ts:ident),*)?) => {
impl <$($($ts),*)?> $crate::HasRepr for ($($($ts,)*)?) {
type GenericRepr = hlist::ty! { $($($ts),*)? };
}
gen_as_hlist_for_tuples! { $($($ts),*)? }
}
}
gen_as_hlist_for_tuples! {T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12}
// =============================
// === KnownLast / KnownInit ===
// =============================
macro_rules! gen_known_last {
() => {};
($t:ident $(,$($ts:ident),*)?) => {
impl<X $(,$($ts),*)?> $crate::KnownLast for ($($($ts,)*)? X,) { type Last = X; }
gen_known_last! { $($($ts),*)? }
}
}
macro_rules! gen_known_init {
() => {};
($t:ident $(,$($ts:ident),*)?) => {
impl<X $(,$($ts),*)?> $crate::KnownInit for ($($($ts,)*)? X,) { type Init = ($($($ts,)*)?); }
gen_known_init! { $($($ts),*)? }
}
}
gen_known_last!{T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11}
gen_known_init!{T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11}
// ================
// === PushBack ===
// ================
impl<X> hlist::PushBack<X>
for () {
type Output = (X,);
fn push_back(self,x:X) -> Self::Output {
(x,)
}
}
impl<X,T0> hlist::PushBack<X>
for (T0,) {
type Output = (T0,X);
fn push_back(self,x:X) -> Self::Output {
(self.0,x)
}
}
impl<X,T0,T1> hlist::PushBack<X>
for (T0,T1) {
type Output = (T0,T1,X);
fn push_back(self,x:X) -> Self::Output {
(self.0,self.1,x)
}
}
impl<X,T0,T1,T2> hlist::PushBack<X>
for (T0,T1,T2) {
type Output = (T0,T1,T2,X);
fn push_back(self,x:X) -> Self::Output {
(self.0,self.1,self.2,x)
}
}
impl<X,T0,T1,T2,T3> hlist::PushBack<X>
for (T0,T1,T2,T3) {
type Output = (T0,T1,T2,T3,X);
fn push_back(self,x:X) -> Self::Output {
(self.0,self.1,self.2,self.3,x)
}
}
impl<X,T0,T1,T2,T3,T4> hlist::PushBack<X>
for (T0,T1,T2,T3,T4) {
type Output = (T0,T1,T2,T3,T4,X);
fn push_back(self,x:X) -> Self::Output {
(self.0,self.1,self.2,self.3,self.4,x)
}
}
impl<X,T0,T1,T2,T3,T4,T5> hlist::PushBack<X>
for (T0,T1,T2,T3,T4,T5) {
type Output = (T0,T1,T2,T3,T4,T5,X);
fn push_back(self,x:X) -> Self::Output {
(self.0,self.1,self.2,self.3,self.4,self.5,x)
}
}
impl<X,T0,T1,T2,T3,T4,T5,T6> hlist::PushBack<X>
for (T0,T1,T2,T3,T4,T5,T6) {
type Output = (T0,T1,T2,T3,T4,T5,T6,X);
fn push_back(self,x:X) -> Self::Output {
(self.0,self.1,self.2,self.3,self.4,self.5,self.6,x)
}
}
impl<X,T0,T1,T2,T3,T4,T5,T6,T7> hlist::PushBack<X>
for (T0,T1,T2,T3,T4,T5,T6,T7) {
type Output = (T0,T1,T2,T3,T4,T5,T6,T7,X);
fn push_back(self,x:X) -> Self::Output {
(self.0,self.1,self.2,self.3,self.4,self.5,self.6,self.7,x)
}
}
impl<X,T0,T1,T2,T3,T4,T5,T6,T7,T8> hlist::PushBack<X>
for (T0,T1,T2,T3,T4,T5,T6,T7,T8) {
type Output = (T0,T1,T2,T3,T4,T5,T6,T7,T8,X);
fn push_back(self,x:X) -> Self::Output {
(self.0,self.1,self.2,self.3,self.4,self.5,self.6,self.7,self.8,x)
}
}
impl<X,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9> hlist::PushBack<X>
for (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9) {
type Output = (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,X);
fn push_back(self,x:X) -> Self::Output {
(self.0,self.1,self.2,self.3,self.4,self.5,self.6,self.7,self.8,self.9,x)
}
}
impl<X,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10> hlist::PushBack<X>
for (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10) {
type Output = (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,X);
fn push_back(self,x:X) -> Self::Output {
(self.0,self.1,self.2,self.3,self.4,self.5,self.6,self.7,self.8,self.9,self.10,x)
}
}
// ===============
// === PopBack ===
// ===============
impl<T0> hlist::PopBack
for (T0,) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.0,())
}
}
impl<T0,T1> hlist::PopBack
for (T0,T1) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.1,(self.0,))
}
}
impl<T0,T1,T2> hlist::PopBack
for (T0,T1,T2) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.2,(self.0,self.1))
}
}
impl<T0,T1,T2,T3> hlist::PopBack
for (T0,T1,T2,T3) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.3,(self.0,self.1,self.2))
}
}
impl<T0,T1,T2,T3,T4> hlist::PopBack
for (T0,T1,T2,T3,T4) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.4,(self.0,self.1,self.2,self.3))
}
}
impl<T0,T1,T2,T3,T4,T5> hlist::PopBack
for (T0,T1,T2,T3,T4,T5) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.5,(self.0,self.1,self.2,self.3,self.4))
}
}
impl<T0,T1,T2,T3,T4,T5,T6> hlist::PopBack
for (T0,T1,T2,T3,T4,T5,T6) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.6,(self.0,self.1,self.2,self.3,self.4,self.5))
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7> hlist::PopBack
for (T0,T1,T2,T3,T4,T5,T6,T7) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.7,(self.0,self.1,self.2,self.3,self.4,self.5,self.6))
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8> hlist::PopBack
for (T0,T1,T2,T3,T4,T5,T6,T7,T8) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.8,(self.0,self.1,self.2,self.3,self.4,self.5,self.6,self.7))
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9> hlist::PopBack
for (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.9,(self.0,self.1,self.2,self.3,self.4,self.5,self.6,self.7,self.8))
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10> hlist::PopBack
for (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.10,(self.0,self.1,self.2,self.3,self.4,self.5,self.6,self.7,self.8,self.9))
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11> hlist::PopBack
for (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11) {
fn pop_back(self) -> (Self::Last,Self::Init) {
(self.11,(self.0,self.1,self.2,self.3,self.4,self.5,self.6,self.7,self.8,self.9,self.10))
}
}
// =================================
// === Conversion Tuple -> HList ===
// =================================
impl From<()>
for hlist::ty![] {
#[inline(always)]
fn from(_:()) -> Self {
hlist::new![]
}
}
impl<T0> From<(T0,)>
for hlist::ty![T0] {
#[inline(always)]
fn from(t:(T0,)) -> Self {
hlist::new![t.0]
}
}
impl<T0,T1> From<(T0,T1,)>
for hlist::ty![T0,T1] {
#[inline(always)]
fn from(t:(T0,T1,)) -> Self {
hlist::new![t.0,t.1]
}
}
impl<T0,T1,T2> From<(T0,T1,T2,)>
for hlist::ty![T0,T1,T2] {
#[inline(always)]
fn from(t:(T0,T1,T2,)) -> Self {
hlist::new![t.0,t.1,t.2]
}
}
impl<T0,T1,T2,T3> From<(T0,T1,T2,T3,)>
for hlist::ty![T0,T1,T2,T3] {
#[inline(always)]
fn from(t:(T0,T1,T2,T3,)) -> Self {
hlist::new![t.0,t.1,t.2,t.3]
}
}
impl<T0,T1,T2,T3,T4> From<(T0,T1,T2,T3,T4,)>
for hlist::ty![T0,T1,T2,T3,T4] {
#[inline(always)]
fn from(t:(T0,T1,T2,T3,T4,)) -> Self {
hlist::new![t.0,t.1,t.2,t.3,t.4]
}
}
impl<T0,T1,T2,T3,T4,T5> From<(T0,T1,T2,T3,T4,T5,)>
for hlist::ty![T0,T1,T2,T3,T4,T5] {
#[inline(always)]
fn from(t:(T0,T1,T2,T3,T4,T5,)) -> Self {
hlist::new![t.0,t.1,t.2,t.3,t.4,t.5]
}
}
impl<T0,T1,T2,T3,T4,T5,T6> From<(T0,T1,T2,T3,T4,T5,T6,)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6] {
#[inline(always)]
fn from(t:(T0,T1,T2,T3,T4,T5,T6,)) -> Self {
hlist::new![t.0,t.1,t.2,t.3,t.4,t.5,t.6]
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7> From<(T0,T1,T2,T3,T4,T5,T6,T7,)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6,T7] {
#[inline(always)]
fn from(t:(T0,T1,T2,T3,T4,T5,T6,T7,)) -> Self {
hlist::new![t.0,t.1,t.2,t.3,t.4,t.5,t.6,t.7]
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8> From<(T0,T1,T2,T3,T4,T5,T6,T7,T8,)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6,T7,T8] {
#[inline(always)]
fn from(t:(T0,T1,T2,T3,T4,T5,T6,T7,T8,)) -> Self {
hlist::new![t.0,t.1,t.2,t.3,t.4,t.5,t.6,t.7,t.8]
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9> From<(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6,T7,T8,T9] {
#[inline(always)]
fn from(t:(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,)) -> Self {
hlist::new![t.0,t.1,t.2,t.3,t.4,t.5,t.6,t.7,t.8,t.9]
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10> From<(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10] {
#[inline(always)]
fn from(t:(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,)) -> Self {
hlist::new![t.0,t.1,t.2,t.3,t.4,t.5,t.6,t.7,t.8,t.9,t.10]
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11> From<(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11] {
#[inline(always)]
fn from(t:(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,)) -> Self {
hlist::new![t.0,t.1,t.2,t.3,t.4,t.5,t.6,t.7,t.8,t.9,t.10,t.11]
}
}
// =================================
// === Conversion HList -> Tuple ===
// =================================
impl Into<()>
for hlist::ty![] {
#[inline(always)]
fn into(self) {}
}
impl<T0> Into<(T0,)>
for hlist::ty![T0] {
#[inline(always)]
fn into(self) -> (T0,) {
let hlist::pat![t0] = self;
(t0,)
}
}
impl<T0,T1> Into<(T0,T1)>
for hlist::ty![T0,T1] {
#[inline(always)]
fn into(self) -> (T0,T1) {
let hlist::pat![t0,t1] = self;
(t0,t1)
}
}
impl<T0,T1,T2> Into<(T0,T1,T2)>
for hlist::ty![T0,T1,T2] {
#[inline(always)]
fn into(self) -> (T0,T1,T2) {
let hlist::pat![t0,t1,t2] = self;
(t0,t1,t2)
}
}
impl<T0,T1,T2,T3> Into<(T0,T1,T2,T3)>
for hlist::ty![T0,T1,T2,T3] {
#[inline(always)]
fn into(self) -> (T0,T1,T2,T3) {
let hlist::pat![t0,t1,t2,t3] = self;
(t0,t1,t2,t3)
}
}
impl<T0,T1,T2,T3,T4> Into<(T0,T1,T2,T3,T4)>
for hlist::ty![T0,T1,T2,T3,T4] {
#[inline(always)]
fn into(self) -> (T0,T1,T2,T3,T4) {
let hlist::pat![t0,t1,t2,t3,t4] = self;
(t0,t1,t2,t3,t4)
}
}
impl<T0,T1,T2,T3,T4,T5> Into<(T0,T1,T2,T3,T4,T5)>
for hlist::ty![T0,T1,T2,T3,T4,T5] {
#[inline(always)]
fn into(self) -> (T0,T1,T2,T3,T4,T5) {
let hlist::pat![t0,t1,t2,t3,t4,t5] = self;
(t0,t1,t2,t3,t4,t5)
}
}
impl<T0,T1,T2,T3,T4,T5,T6> Into<(T0,T1,T2,T3,T4,T5,T6)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6] {
#[inline(always)]
fn into(self) -> (T0,T1,T2,T3,T4,T5,T6) {
let hlist::pat![t0,t1,t2,t3,t4,t5,t6] = self;
(t0,t1,t2,t3,t4,t5,t6)
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7> Into<(T0,T1,T2,T3,T4,T5,T6,T7)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6,T7] {
#[inline(always)]
fn into(self) -> (T0,T1,T2,T3,T4,T5,T6,T7) {
let hlist::pat![t0,t1,t2,t3,t4,t5,t6,t7] = self;
(t0,t1,t2,t3,t4,t5,t6,t7)
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8> Into<(T0,T1,T2,T3,T4,T5,T6,T7,T8)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6,T7,T8] {
#[inline(always)]
fn into(self) -> (T0,T1,T2,T3,T4,T5,T6,T7,T8) {
let hlist::pat![t0,t1,t2,t3,t4,t5,t6,t7,t8] = self;
(t0,t1,t2,t3,t4,t5,t6,t7,t8)
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9> Into<(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6,T7,T8,T9] {
#[inline(always)]
fn into(self) -> (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9) {
let hlist::pat![t0,t1,t2,t3,t4,t5,t6,t7,t8,t9] = self;
(t0,t1,t2,t3,t4,t5,t6,t7,t8,t9)
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10> Into<(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10] {
#[inline(always)]
fn into(self) -> (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10) {
let hlist::pat![t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10] = self;
(t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10)
}
}
impl<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11> Into<(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11)>
for hlist::ty![T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11] {
#[inline(always)]
fn into(self) -> (T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11) {
let hlist::pat![t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11] = self;
(t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11)
}
}
// ==============================
// === HasTupleRepr for HList ===
// ==============================
impl HasTupleRepr
for hlist::ty![] {
type TupleRepr = ();
}
impl<T1> HasTupleRepr
for hlist::ty![T1] {
type TupleRepr = (T1,);
}
impl<T1,T2> HasTupleRepr
for hlist::ty![T1,T2] {
type TupleRepr = (T1,T2);
}
impl<T1,T2,T3> HasTupleRepr
for hlist::ty![T1,T2,T3] {
type TupleRepr = (T1,T2,T3);
}
impl<T1,T2,T3,T4> HasTupleRepr
for hlist::ty![T1,T2,T3,T4] {
type TupleRepr = (T1,T2,T3,T4);
}
impl<T1,T2,T3,T4,T5> HasTupleRepr
for hlist::ty![T1,T2,T3,T4,T5] {
type TupleRepr = (T1,T2,T3,T4,T5);
}
impl<T1,T2,T3,T4,T5,T6> HasTupleRepr
for hlist::ty![T1,T2,T3,T4,T5,T6] {
type TupleRepr = (T1,T2,T3,T4,T5,T6);
}
impl<T1,T2,T3,T4,T5,T6,T7> HasTupleRepr
for hlist::ty![T1,T2,T3,T4,T5,T6,T7] {
type TupleRepr = (T1,T2,T3,T4,T5,T6,T7);
}
impl<T1,T2,T3,T4,T5,T6,T7,T8> HasTupleRepr
for hlist::ty![T1,T2,T3,T4,T5,T6,T7,T8] {
type TupleRepr = (T1,T2,T3,T4,T5,T6,T7,T8);
}
impl<T1,T2,T3,T4,T5,T6,T7,T8,T9> HasTupleRepr
for hlist::ty![T1,T2,T3,T4,T5,T6,T7,T8,T9] {
type TupleRepr = (T1,T2,T3,T4,T5,T6,T7,T8,T9);
}
impl<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10> HasTupleRepr
for hlist::ty![T1,T2,T3,T4,T5,T6,T7,T8,T9,T10] {
type TupleRepr = (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10);
}
impl<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11> HasTupleRepr
for hlist::ty![T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11] {
type TupleRepr = (T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11);
}
// =================
// === HasItemAt ===
// =================
macro_rules! gen_has_item_at {
($at:ident $p:tt) => {};
($at:ident [$($p:ident),*] $t:ident $(,$($ts:ident),*)?) => {
impl<$($p,)* X $(,$($ts),*)?> $crate::HasItemAt<$at> for ($($p,)*X,$($($ts,)*)?) {
type Item = X;
}
gen_has_item_at! { $at [$($p),*] $($($ts),*)? }
}
}
gen_has_item_at!{U0 [] T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11}
gen_has_item_at!{U1 [T0] T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11}
gen_has_item_at!{U2 [T0,T1] T2,T3,T4,T5,T6,T7,T8,T9,T10,T11}
gen_has_item_at!{U3 [T0,T1,T2] T3,T4,T5,T6,T7,T8,T9,T10,T11}
gen_has_item_at!{U4 [T0,T1,T2,T3] T4,T5,T6,T7,T8,T9,T10,T11}
gen_has_item_at!{U5 [T0,T1,T2,T3,T4] T5,T6,T7,T8,T9,T10,T11}
gen_has_item_at!{U6 [T0,T1,T2,T3,T4,T5] T6,T7,T8,T9,T10,T11}
gen_has_item_at!{U7 [T0,T1,T2,T3,T4,T5,T6] T7,T8,T9,T10,T11}
gen_has_item_at!{U8 [T0,T1,T2,T3,T4,T5,T6,T7] T8,T9,T10,T11}
gen_has_item_at!{U9 [T0,T1,T2,T3,T4,T5,T6,T7,T8] T9,T10,T11}
gen_has_item_at!{U10 [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9] T10,T11}
gen_has_item_at!{U11 [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10] T11}
// =================
// === GetItemAt ===
// =================
macro_rules! gen_get_item_at {
($at:ident $num:tt $p:tt) => {};
($at:ident $num:tt [$($p:ident),*] $t:ident $(,$($ts:ident),*)?) => {
impl<$($p,)* X $(,$($ts),*)?> $crate::GetItemAt<$at> for ($($p,)*X,$($($ts,)*)?) {
fn get_item_at(&self) -> &X { &self.$num }
}
gen_get_item_at! { $at $num [$($p),*] $($($ts),*)? }
}
}
gen_get_item_at!{U0 0 [] T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11}
gen_get_item_at!{U1 1 [T0] T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11}
gen_get_item_at!{U2 2 [T0,T1] T2,T3,T4,T5,T6,T7,T8,T9,T10,T11}
gen_get_item_at!{U3 3 [T0,T1,T2] T3,T4,T5,T6,T7,T8,T9,T10,T11}
gen_get_item_at!{U4 4 [T0,T1,T2,T3] T4,T5,T6,T7,T8,T9,T10,T11}
gen_get_item_at!{U5 5 [T0,T1,T2,T3,T4] T5,T6,T7,T8,T9,T10,T11}
gen_get_item_at!{U6 6 [T0,T1,T2,T3,T4,T5] T6,T7,T8,T9,T10,T11}
gen_get_item_at!{U7 7 [T0,T1,T2,T3,T4,T5,T6] T7,T8,T9,T10,T11}
gen_get_item_at!{U8 8 [T0,T1,T2,T3,T4,T5,T6,T7] T8,T9,T10,T11}
gen_get_item_at!{U9 9 [T0,T1,T2,T3,T4,T5,T6,T7,T8] T9,T10,T11}
gen_get_item_at!{U10 10 [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9] T10,T11}
gen_get_item_at!{U11 11 [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10] T11}

View File

@ -0,0 +1,26 @@
[package]
name = "logger"
version = "0.1.0"
authors = ["Enso Team <enso-dev@enso.org>"]
edition = "2018"
description = "A generic logging library."
readme = "README.md"
homepage = "https://github.com/enso-org/enso/lib/rust/enso-logger"
repository = "https://github.com/enso-org/enso"
license-file = "../../../LICENSE"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = []
[dependencies]
enso-prelude = { version = "0.1.0" , path = "../enso-prelude" }
enso-shapely = { version = "0.1.0" , path = "../enso-shapely/impl" }
wasm-bindgen = { version = "=0.2.58", features = ["nightly"] }
[dependencies.web-sys]
version = "0.3.4"
features = ['console']

View File

@ -0,0 +1,2 @@
# Enso Logger
A generic logging library.

View File

@ -0,0 +1,35 @@
//! Contains definition of trivial logger that discards all messages except warnings and errors.
use enso_prelude::*;
use crate::Message;
use crate::AnyLogger;
use crate::enabled;
use enso_shapely::CloneRef;
use std::fmt::Debug;
// ==============
// === Logger ===
// ==============
/// Trivial logger that discards all messages except warnings and errors.
#[derive(Clone,CloneRef,Debug,Default)]
pub struct Logger {
enabled : enabled::Logger,
}
// === Impls ===
impls!{ From + &From <enabled::Logger> for Logger { |logger| Self::new(logger.path()) }}
impl AnyLogger for Logger {
type Owned = Self;
fn new (path:impl Into<ImString>) -> Self { Self {enabled : enabled::Logger::new(path) } }
fn path (&self) -> &str { self.enabled.path() }
fn warning (&self, msg:impl Message) { self.enabled.warning (msg) }
fn error (&self, msg:impl Message) { self.enabled.error (msg) }
}

View File

@ -0,0 +1,96 @@
//! Contains implementation of default logger.
use enso_prelude::*;
use crate::AnyLogger;
use crate::Message;
use enso_shapely::CloneRef;
use std::fmt::Debug;
#[cfg(target_arch = "wasm32")]
use web_sys::console;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::JsValue;
// ==============
// === Logger ===
// ==============
/// Default Logger implementation.
#[derive(Clone,CloneRef,Debug,Default)]
pub struct Logger {
/// Path that is used as an unique identifier of this logger.
path : ImString,
#[cfg(not(target_arch="wasm32"))]
indent : Rc<Cell<usize>>,
}
#[cfg(not(target_arch="wasm32"))]
impl Logger {
fn format(&self, msg:impl Message) -> String {
let indent = " ".repeat(4*self.indent.get());
msg.with(|s|iformat!("{indent}[{self.path}] {s}"))
}
fn inc_indent(&self) {
self.indent.update(|t|t+1);
}
fn dec_indent(&self) {
self.indent.update(|t|t-1);
}
}
#[cfg(target_arch="wasm32")]
impl Logger {
fn format(&self, msg:impl Message) -> JsValue {
msg.with(|s|iformat!("[{self.path}] {s}")).into()
}
}
#[cfg(not(target_arch="wasm32"))]
impl AnyLogger for Logger {
type Owned = Self;
fn new(path:impl Into<ImString>) -> Self {
let path = path.into();
let indent = default();
Self {path,indent}
}
fn path (&self) -> &str { &self.path }
fn trace (&self, msg:impl Message) { println!("{}",self.format(msg)) }
fn debug (&self, msg:impl Message) { println!("{}",self.format(msg)) }
fn info (&self, msg:impl Message) { println!("{}",self.format(msg)) }
fn warning (&self, msg:impl Message) { println!("[WARNING] {}",self.format(msg)) }
fn error (&self, msg:impl Message) { println!("[ERROR] {}",self.format(msg)) }
fn group_begin (&self, msg:impl Message) { println!("{}",self.format(msg)); self.inc_indent() }
fn group_end (&self) { self.dec_indent() }
}
#[cfg(target_arch="wasm32")]
impl AnyLogger for Logger {
type Owned = Self;
fn new(path:impl Into<ImString>) -> Self {
let path = path.into();
Self {path}
}
fn path (&self) -> &str { &self.path }
fn trace (&self, msg:impl Message) { console::trace_1 (&self.format(msg)) }
fn debug (&self, msg:impl Message) { console::debug_1 (&self.format(msg)) }
fn info (&self, msg:impl Message) { console::info_1 (&self.format(msg)) }
fn warning (&self, msg:impl Message) { console::warn_1 (&self.format(msg)) }
fn error (&self, msg:impl Message) { console::error_1 (&self.format(msg)) }
fn group_begin (&self, msg:impl Message) { console::group_1 (&self.format(msg)) }
fn group_end (&self) { console::group_end() }
}
// ===================
// === Conversions ===
// ===================
impls!{ From + &From <crate::disabled::Logger> for Logger { |logger| Self::new(logger.path()) }}

View File

@ -0,0 +1,235 @@
//! This crate contains implementation of logging interface.
#![feature(cell_update)]
#![deny(unconditional_recursion)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unsafe_code)]
#![warn(unused_import_braces)]
pub mod disabled;
pub mod enabled;
use enso_prelude::*;
// ==============
// === Message ===
// ==============
/// Message that can be logged.
pub trait Message {
/// Turns message into `&str` and passes it to input function.
fn with<T,F:FnOnce(&str)->T>(&self, f:F) -> T;
}
impl Message for &str {
fn with<T,F:FnOnce(&str)->T>(&self, f:F) -> T {
f(self)
}
}
impl<G:Fn()->S, S:AsRef<str>> Message for G {
fn with<T,F:FnOnce(&str)->T>(&self, f:F) -> T {
f(self().as_ref())
}
}
// =================
// === AnyLogger ===
// =================
/// Interface common to all loggers.
pub trait AnyLogger {
/// Owned type of the logger.
type Owned;
/// Creates a new logger. Path should be a unique identifier for this logger.
fn new(path:impl Into<ImString>) -> Self::Owned;
/// Path that is used as an unique identifier of this logger.
fn path(&self) -> &str;
/// Creates a new logger with this logger as a parent.
fn sub(logger:impl AnyLogger, path:impl Into<ImString>) -> Self::Owned {
let path = path.into();
let super_path = logger.path();
if super_path.is_empty() { Self::new(path) }
else { Self::new(iformat!("{super_path}.{path}")) }
}
/// Creates a logger from AnyLogger.
fn from_logger(logger:impl AnyLogger) -> Self::Owned {
Self::new(logger.path())
}
/// Evaluates function `f` and visually groups all logs will occur during its execution.
fn group<T,F:FnOnce() -> T>(&self, msg:impl Message, f:F) -> T {
self.group_begin(msg);
let out = f();
self.group_end();
out
}
/// Log with stacktrace and info level verbosity.
fn trace(&self, _msg:impl Message) {}
/// Log with debug level verbosity
fn debug(&self, _msg:impl Message) {}
/// Log with info level verbosity.
fn info(&self, _msg:impl Message) {}
/// Log with warning level verbosity.
fn warning(&self, _msg:impl Message) {}
/// Log with error level verbosity.
fn error(&self, _msg:impl Message) {}
/// Visually groups all logs between group_begin and group_end.
fn group_begin(&self, _msg:impl Message) {}
/// Visually groups all logs between group_begin and group_end.
fn group_end(&self) {}
}
impl<T:AnyLogger> AnyLogger for &T {
type Owned = T::Owned;
fn path (&self) -> &str { T::path(self) }
fn new (path:impl Into<ImString>) -> Self::Owned { T::new(path) }
fn trace (&self, msg:impl Message) { T::trace (self,msg) }
fn debug (&self, msg:impl Message) { T::debug (self,msg) }
fn info (&self, msg:impl Message) { T::info (self,msg) }
fn warning (&self, msg:impl Message) { T::warning (self,msg) }
fn error (&self, msg:impl Message) { T::error (self,msg) }
fn group_begin (&self, msg:impl Message) { T::group_begin (self,msg) }
fn group_end (&self) { T::group_end (self) }
}
// ==============
// === Macros ===
// ==============
/// Shortcut for `|| format!(..)`.
#[macro_export]
macro_rules! fmt {
($($arg:tt)*) => (||(format!($($arg)*)))
}
/// Evaluates expression and visually groups all logs will occur during its execution.
#[macro_export]
macro_rules! group {
($logger:expr, $message:tt, {$($body:tt)*}) => {{
let __logger = $logger.clone();
__logger.group_begin(|| iformat!{$message});
let out = {$($body)*};
__logger.group_end();
out
}};
}
/// Logs a message on on given level.
#[macro_export]
macro_rules! log_template {
($method:ident $logger:expr, $message:tt $($rest:tt)*) => {
$crate::log_template_impl! {$method $logger, iformat!($message) $($rest)*}
};
}
/// Logs a message on on given level.
#[macro_export]
macro_rules! log_template_impl {
($method:ident $logger:expr, $expr:expr) => {{
$logger.$method(|| $expr);
}};
($method:ident $logger:expr, $expr:expr, $body:tt) => {{
let __logger = $logger.clone();
__logger.group_begin(|| $expr);
let out = $body;
__logger.group_end();
out
}};
}
/// Logs an internal error with descriptive message.
#[macro_export]
macro_rules! with_internal_bug_message { ($f:ident $($args:tt)*) => { $crate::$f! {
"This is a bug. Please report it and and provide us with as much information as \
possible at https://github.com/luna/enso/issues. Thank you!"
$($args)*
}};}
/// Logs an internal error.
#[macro_export]
macro_rules! log_internal_bug_template {
($($toks:tt)*) => {
$crate::with_internal_bug_message! { log_internal_bug_template_impl $($toks)* }
};
}
/// Logs an internal error.
#[macro_export]
macro_rules! log_internal_bug_template_impl {
($note:tt $method:ident $logger:expr, $message:tt $($rest:tt)*) => {
$crate::log_template_impl! {$method $logger,
format!("Internal Error. {}\n\n{}",iformat!($message),$note) $($rest)*
}
};
}
/// Log with stacktrace and level:info.
#[macro_export]
macro_rules! trace {
($($toks:tt)*) => {
$crate::log_template! {trace $($toks)*}
};
}
/// Log with level:debug
#[macro_export]
macro_rules! debug {
($($toks:tt)*) => {
$crate::log_template! {debug $($toks)*}
};
}
/// Log with level:info.
#[macro_export]
macro_rules! info {
($($toks:tt)*) => {
$crate::log_template! {info $($toks)*}
};
}
/// Log with level:warning.
#[macro_export]
macro_rules! warning {
($($toks:tt)*) => {
$crate::log_template! {warning $($toks)*}
};
}
/// Log with level:error.
#[macro_export]
macro_rules! error {
($($toks:tt)*) => {
$crate::log_template! {error $($toks)*}
};
}
/// Logs an internal warning.
#[macro_export]
macro_rules! internal_warning {
($($toks:tt)*) => {
$crate::log_internal_bug_template! {warning $($toks)*}
};
}

View File

@ -0,0 +1,34 @@
[package]
name = "enso-macro-utils"
version = "0.1.0"
authors = ["Enso Team <enso-dev@enso.org>"]
edition = "2018"
description = "Utilities for writing macros."
readme = "README.md"
homepage = "https://github.com/enso-org/enso/lib/rust/enso-macro-utils"
repository = "https://github.com/enso-org/enso"
license-file = "../../../LICENSE"
keywords = ["macro", "utility"]
categories = ["development-tools::procedural-macro-helpers"]
publish = true
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
[dependencies.syn]
version = "1.0"
features = [
'extra-traits',
'full', # for syn::ItemStruct
'visit'
]
[dev-dependencies]
wasm-bindgen-test = "0.2"

View File

@ -0,0 +1,2 @@
# Macro Utils
This crate provides some utilities useful for writing macros.

View File

@ -0,0 +1,358 @@
//! A number of helper functions meant to be used in the procedural enso-shapely-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>(&quoted_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, &param)
};
// 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(&param));
}
for independent in independents {
assert!(!depends(independent), "{} must not depend on {}"
, repr(&independent), repr(&param));
}
}
#[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");
}
}

View File

@ -0,0 +1,19 @@
[package]
name = "optics"
version = "0.1.0"
authors = ["Enso Team <enso-dev@enso.org>"]
edition = "2018"
description = "A library providing lenses and prisms."
readme = "README.md"
homepage = "https://github.com/enso-org/enso/lib/rust/enso-optics"
repository = "https://github.com/enso-org/enso"
license-file = "../../../LICENSE"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
[dependencies]
enso-prelude = { version = "0.1.0", path = "../enso-prelude" }

View File

@ -0,0 +1,2 @@
# Enso Optics
A library providing lenses and prisms.

View File

@ -0,0 +1,540 @@
#![warn(unsafe_code)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(dead_code)]
#![allow(unused_macros)]
#![allow(clippy::option_map_unit_fn)]
use enso_prelude::*;
// ================
// === TypeList ===
// ================
trait HList {}
impl HList for Nil {}
impl<Head,Tail> HList for Cons<Head,Tail> where Head:?Sized, Tail:?Sized {}
struct Nil;
struct Cons<Head,Tail>(PhantomData2<Head,Tail>) where Head:?Sized, Tail:?Sized;
// === Instances ===
impl<Head:?Sized, Tail:?Sized>
Cons<Head,Tail> {
pub fn new() -> Self { Self::default() }
}
impl<Head:?Sized, Tail:?Sized>
Default for Cons<Head,Tail> {
fn default() -> Self { Self(default()) }
}
// === Append ===
type Append<El, Els> = <Els as Appendable<El>>::Result;
trait Appendable<T:?Sized> { type Result; }
impl<T:?Sized>
Appendable<T> for Nil {
type Result = Cons<T, Nil>;
}
impl<T:?Sized, Head:?Sized, Tail:?Sized+Appendable<T>>
Appendable<T> for Cons<Head, Tail> {
type Result = Cons<Head, Append<T, Tail>>;
}
// =============
// === Field ===
// =============
type Field<T, Field> = <T as HasField<Field>>::Result;
trait HasField<Field> { type Result; }
// ==============
// === Getter ===
// ==============
trait Getter<T>: HasField<T> {
fn get (& self) -> & Field<Self, T>;
fn get_mut (&mut self) -> &mut Field<Self, T>;
}
trait OptGetter<T>: HasField<T> {
fn get (& self) -> Option <& Field<Self, T>>;
fn get_mut (&mut self) -> Option <&mut Field<Self, T>>;
}
// ================
// === Resolver ===
// ================
// === FieldResolver ===
type NestedField<T, Path> = <Path as FieldResolver<T>>::Result;
trait FieldResolver<T: ?Sized> { type Result; }
impl<T>
FieldResolver<T> for Nil {
type Result = T;
}
impl<Head, Tail, T>
FieldResolver<T> for Cons<Head, Tail>
where T: HasField<Head>, Tail: FieldResolver<Field<T, Head>> {
type Result = NestedField<Field<T, Head>, Tail>;
}
// === Resolver ===
trait Resolver<T>: FieldResolver<T> {
fn resolve (t: & T) -> & NestedField<T, Self>;
fn resolve_mut (t: &mut T) -> &mut NestedField<T, Self>;
}
trait OptResolver<T>: FieldResolver<T> {
fn resolve (t: & T) -> Option<& NestedField<T, Self>>;
fn resolve_mut (t: &mut T) -> Option<&mut NestedField<T, Self>>;
}
impl<T> Resolver<T> for Nil {
fn resolve (t: & T) -> & NestedField<T, Self> { t }
fn resolve_mut (t: &mut T) -> &mut NestedField<T, Self> { t }
}
impl<T> OptResolver<T> for Nil {
fn resolve (t: & T) -> Option<& NestedField<T, Self>> { Some(t) }
fn resolve_mut (t: &mut T) -> Option<&mut NestedField<T, Self>> { Some(t) }
}
impl<Head:'static,Tail,T> Resolver<T> for Cons<Head, Tail>
where T: Getter<Head>, Tail: Resolver<Field<T, Head>> {
fn resolve(t: &T) -> &NestedField<T, Self> {
let head = Getter::<Head>::get(t);
<Tail as Resolver<Field<T, Head>>>::resolve(head)
}
fn resolve_mut(t: &mut T) -> &mut NestedField<T, Self> {
let head = Getter::<Head>::get_mut(t);
<Tail as Resolver<Field<T, Head>>>::resolve_mut(head)
}
}
impl<Head:'static,Tail,T> OptResolver<T> for Cons<Head, Tail>
where T: OptGetter<Head>, Tail: OptResolver<Field<T, Head>> {
fn resolve(t: &T) -> Option<&NestedField<T, Self>> {
OptGetter::<Head>::get(t)
.and_then(|t| <Tail as OptResolver<Field<T, Head>>>::resolve(t))
}
fn resolve_mut(t: &mut T) -> Option<&mut NestedField<T, Self>> {
OptGetter::<Head>::get_mut(t)
.and_then(|t| <Tail as OptResolver<Field<T, Head>>>::resolve_mut(t))
}
}
// ============
// === Lens ===
// ============
struct Lens <Src,Tgt,Path>(PhantomData3<Src,Tgt,Path>);
struct OptLens <Src,Tgt,Path>(PhantomData3<Src,Tgt,Path>);
impl<Src,Tgt,Path> Copy for Lens<Src,Tgt,Path> {}
impl<Src,Tgt,Path> Clone for Lens<Src,Tgt,Path> {
fn clone(&self) -> Self { Lens::new() }
}
impl<Src,Tgt,Path> Copy for OptLens<Src,Tgt,Path> {}
impl<Src,Tgt,Path> Clone for OptLens<Src,Tgt,Path> {
fn clone(&self) -> Self { OptLens::new() }
}
impl<Src,Tgt,Path> OptLens<Src,Tgt,Path> {
pub fn resolve(self, t: &Src) -> Option<&NestedField<Src, Path>>
where Path: OptResolver<Src> {
<Path as OptResolver<Src>>::resolve(t)
}
pub fn resolve_mut(self, t: &mut Src) -> Option<&mut NestedField<Src, Path>>
where Path: OptResolver<Src> {
<Path as OptResolver<Src>>::resolve_mut(t)
}
}
impl<Src,Tgt,Path> Lens<Src,Tgt,Path> {
pub fn resolve(self, t: &Src) -> &NestedField<Src, Path>
where Path: Resolver<Src> {
<Path as Resolver<Src>>::resolve(&t)
}
}
impl<Src,Tgt,Path> Lens<Src,Tgt,Path> {
pub fn new() -> Self { default() }
}
impl<Src,Tgt,Path> Default for Lens<Src,Tgt,Path> {
fn default() -> Self { Self(default()) }
}
impl<Src,Tgt,Path> OptLens<Src,Tgt,Path> {
pub fn new() -> Self { default() }
}
impl<Src,Tgt,Path> Default for OptLens<Src,Tgt,Path> {
fn default() -> Self { Self(default()) }
}
struct BoundLens<'t,Src,Tgt,Path> {
target: &'t Src,
lens: Lens<Src,Tgt,Path>,
}
struct BoundLensMut<'t,Src,Tgt,Path> {
target: &'t mut Src,
lens: Lens<Src,Tgt,Path>,
}
struct BoundOptLens<'t,Src,Tgt,Path> {
target: &'t Src,
lens: OptLens<Src,Tgt,Path>,
}
struct BoundOptLensMut<'t,Src,Tgt,Path> {
target: &'t mut Src,
lens: OptLens<Src,Tgt,Path>,
}
impl<'t,Src,Tgt,Path> BoundLens<'t,Src,Tgt,Path> {
pub fn new(target: &'t Src) -> Self {
let lens = Lens::new();
Self { target, lens }
}
pub fn read(&self) -> &NestedField<Src,Path>
where Path: Resolver<Src> {
self.lens.resolve(self.target)
}
}
impl<'t,Src,Tgt,Path> BoundOptLens<'t,Src,Tgt,Path> {
pub fn new(target: &'t Src) -> Self {
let lens = OptLens::new();
Self { target, lens }
}
pub fn read(&self) -> Option<&NestedField<Src, Path>>
where Path: OptResolver<Src> {
self.lens.resolve(self.target)
}
}
impl<'t,Src:Clone,Tgt,Path> BoundOptLens<'t,Src,Tgt,Path> {
pub fn write(&self, val: NestedField<Src, Path>)
where for<'a> Path: OptResolver<Src>,
OptLens<Src,Tgt,Path>: Copy {
let mut a = (*self.target).clone();
a.lens_mut().unsafe_repath::<Path>().set(val);
}
}
impl<'t,Src,Tgt,Path> BoundOptLensMut<'t,Src,Tgt,Path> {
pub fn new(target: &'t mut Src) -> Self {
let lens = OptLens::new();
Self { target, lens }
}
pub fn get(&mut self) -> Option<&mut NestedField<Src, Path>>
where Path: OptResolver<Src> {
self.lens.resolve_mut(self.target)
}
pub fn set(&mut self, val: NestedField<Src, Path>)
where Path: OptResolver<Src> {
let r = self.get();
r.map(|s| *s = val);
}
pub fn unsafe_repath<Path2>(self) -> BoundOptLensMut<'t,Src,Tgt,Path2> {
BoundOptLensMut {
target: self.target,
lens: OptLens::new(),
}
}
}
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
trait HasLens where Self:Sized {
fn lens(&self) -> BoundOptLens<'_, Self, Self, Nil> {
BoundOptLens::new(self)
}
fn lens_mut(&mut self) -> BoundOptLensMut<'_, Self, Self, Nil> {
BoundOptLensMut::new(self)
}
}
impl<T> HasLens for T {}
macro_rules! mk_lens_field_decl {
($struct_name:ident<$($param:ident),*>{$field_name:ident : $field_type:ty}) => {
paste::item! {
// struct FIELD_bar;
struct [<FIELD_ $field_name>];
// impl HasField<FIELD_bar> for Foo<> {
// type Result = Bar;
// }
impl<$($param),*> HasField<[<FIELD_ $field_name>]> for $struct_name<$($param),*> {
type Result = $field_type;
}
}}}
macro_rules! mk_lenses_for {
($struct_name:ident<$($param:ident),*>{$field_name:ident : $field_type:ty}) => {
paste::item! {
mk_lens_field_decl!($struct_name<$($param),*>{$field_name:$field_type});
// impl Getter<FIELD_bar> for Foo {
// fn get(&self) -> &Field<Self, FIELD_bar> {
// &self.bar
// }
// fn get_mut(&mut self) -> &mut Field<Self, FIELD_bar> {
// &mut self.bar
// }
// }
impl<$($param),*> Getter<[<FIELD_ $field_name>]> for $struct_name<$($param),*> {
fn get(&self) -> &Field<Self, [<FIELD_ $field_name>]> {
&self.$field_name
}
fn get_mut(&mut self) -> &mut Field<Self, [<FIELD_ $field_name>]> {
&mut self.$field_name
}
}
// impl OptGetter<FIELD_bar> for Foo {
// fn get(&self) -> Option<&Field<Self, FIELD_bar>> {
// Some(&self.bar)
// }
// fn get_mut(&mut self) -> Option<&mut Field<Self, FIELD_bar>> {
// Some(&mut self.bar)
// }
// }
impl<$($param),*> OptGetter<[<FIELD_ $field_name>]> for $struct_name<$($param),*> {
fn get(&self) -> Option<&Field<Self, [<FIELD_ $field_name>]>> {
Some(&self.$field_name)
}
fn get_mut(&mut self)
-> Option<&mut Field<Self, [<FIELD_ $field_name>]>> {
Some(&mut self.$field_name)
}
}
// impl<'lens_lifetime, LENS_BEGIN, LENS_NEW_PATH>
// BoundOptLensMut<'lens_lifetime, LENS_BEGIN, Foo, LENS_NEW_PATH>
// where LENS_NEW_PATH: Appendable<FIELD_bar> {
// fn bar(self)
// -> BoundOptLensMut
// < 'lens_lifetime
// , LENS_BEGIN
// , Bar
// , Append<FIELD_bar
// , LENS_NEW_PATH>
// > {
// BoundOptLensMut::new(self.target)
// }
// }
impl<'lens_lifetime, LENS_BEGIN, LENS_NEW_PATH>
BoundOptLensMut<'lens_lifetime, LENS_BEGIN, $struct_name, LENS_NEW_PATH>
where LENS_NEW_PATH: Appendable<[<FIELD_ $field_name>]> {
fn $field_name(self)
-> BoundOptLensMut
< 'lens_lifetime
, LENS_BEGIN
, Field<$struct_name
,[<FIELD_ $field_name>]>
, Append<[<FIELD_ $field_name>]
, LENS_NEW_PATH>
> {
BoundOptLensMut::new(self.target)
}
}
impl<'lens_lifetime, LENS_BEGIN, LENS_NEW_PATH>
BoundOptLens<'lens_lifetime, LENS_BEGIN, $struct_name, LENS_NEW_PATH>
where LENS_NEW_PATH: Appendable<[<FIELD_ $field_name>]> {
fn $field_name(self)
-> BoundOptLens
< 'lens_lifetime
, LENS_BEGIN
, Field<$struct_name
,[<FIELD_ $field_name>]>
, Append<[<FIELD_ $field_name>]
, LENS_NEW_PATH>
> {
BoundOptLens::new(self.target)
}
}
}};
($struct_name:ident<$($param:ident),*> :: $cons_name:ident {$field_name:ident : $field_type:ty}) => {
paste::item! {
mk_lens_field_decl!($struct_name<$($param),*>{$field_name:$field_type});
// impl OptGetter<FIELD_bar> for Foo {
// fn get(&self) -> Option<&Field<Self, FIELD_bar>> {
// Some(&self.bar)
// }
// fn get_mut(&mut self) -> Option<&mut Field<Self, FIELD_bar>> {
// Some(&mut self.bar)
// }
// }
impl<$($param),*> OptGetter<[<FIELD_ $field_name>]> for $struct_name<$($param),*> {
fn get(&self) -> Option<&Field<Self, [<FIELD_ $field_name>]>> {
match self {
$cons_name(ref $field_name) => Some($field_name),
_ => None
}
}
fn get_mut(&mut self)
-> Option<&mut Field<Self, [<FIELD_ $field_name>]>> {
match self {
$cons_name(ref mut $field_name) => Some($field_name),
_ => None
}
}
}
// impl<'lens_lifetime, LENS_BEGIN, LENS_NEW_PATH>
// BoundOptLensMut<'lens_lifetime, LENS_BEGIN, Foo, LENS_NEW_PATH>
// where LENS_NEW_PATH: Appendable<FIELD_bar> {
// fn bar(self)
// -> BoundOptLensMut
// < 'lens_lifetime
// , LENS_BEGIN
// , Field<FIELD_Bar, Foo<>>
// , Append<FIELD_bar, LENS_NEW_PATH>
// > {
// BoundOptLensMut::new(self.target)
// }
// }
impl<'lens_lifetime, LENS_BEGIN, LENS_NEW_PATH, $($param),*>
BoundOptLensMut<'lens_lifetime, LENS_BEGIN, $struct_name<$($param),*>, LENS_NEW_PATH>
where LENS_NEW_PATH: Appendable<[<FIELD_ $field_name>]> {
fn $cons_name(self)
-> BoundOptLensMut
< 'lens_lifetime
, LENS_BEGIN
, Field<$struct_name<$($param),*>,[<FIELD_ $field_name>]>
, Append<[<FIELD_ $field_name>], LENS_NEW_PATH>
> {
BoundOptLensMut::new(self.target)
}
}
impl<'lens_lifetime, LENS_BEGIN, LENS_NEW_PATH, $($param),*>
BoundOptLens<'lens_lifetime, LENS_BEGIN, $struct_name<$($param),*>, LENS_NEW_PATH>
where LENS_NEW_PATH: Appendable<[<FIELD_ $field_name>]> {
fn $cons_name(self)
-> BoundOptLens
< 'lens_lifetime
, LENS_BEGIN
, Field<$struct_name<$($param),*>,[<FIELD_ $field_name>]>
, Append<[<FIELD_ $field_name>], LENS_NEW_PATH>
> {
BoundOptLens::new(self.target)
}
}
}}}
macro_rules! lens {
($base:ident . $($seg:ident).*) => {
$base.lens().$($seg()).*
}
}
macro_rules! lens_mut {
($base:ident . $($seg:ident).*) => {
$base.lens_mut().$($seg()).*
}
}
mk_lenses_for!(Option<T>::Some{val: T});
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, PartialEq, Eq)]
struct Foo {
bar: Bar,
}
mk_lenses_for!(Foo<>{bar: Bar});
#[derive(Debug, PartialEq, Eq)]
struct Bar {
baz: Option<Baz>,
}
mk_lenses_for!(Bar<>{baz: Option<Baz>});
#[derive(Debug, PartialEq, Eq)]
struct Baz {
qux: Option<Qux>,
}
mk_lenses_for!(Baz<>{qux: Option<Qux>});
#[derive(Debug, PartialEq, Eq)]
struct Qux {
quxx: String,
}
mk_lenses_for!(Qux<>{quxx: String});
#[test]
fn deeply_nested() {
let mut foo = Foo {
bar: Bar {
baz: Some(Baz {
qux: Some(Qux {
quxx: "nice".to_owned(),
}),
}),
},
};
lens_mut!(foo.bar.baz.Some.qux.Some.quxx).set("Hello".into());
assert_eq!(foo, Foo {
bar: Bar {
baz: Some(Baz {
qux: Some(Qux {
quxx: "Hello".to_owned(),
}),
}),
},
})
}
}
pub fn main() {
let mut val: Option<Option<i32>> = Some(Some(17));
val.lens_mut().Some().Some().set(10);
let lens1 = val.lens().Some().Some();
let mut val2 = *lens1.target;
let lm = val2.lens_mut();
let mut lm2 = BoundOptLensMut {
target: lm.target,
lens: lens1.lens,
};
lm2.set(9);
println!("{:?}", val.lens_mut().Some().Some().get());
println!("{:?}", val2.lens_mut().Some().Some().get());
}

View File

@ -0,0 +1,83 @@
[package]
name = "enso-prelude"
version = "0.1.0"
authors = ["Enso Team <enso-dev@enso.org>"]
edition = "2018"
description = "An augmented standard library in the vein of Haskell's prelude."
readme = "README.md"
homepage = "https://github.com/enso-org/enso/lib/rust/enso-prelude"
repository = "https://github.com/enso-org/enso"
license-file = "../../../LICENSE"
keywords = ["prelude", "standard-library"]
categories = ["algorithms"]
publish = true
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
enso-shapely = { version = "0.1.0" , path = "../enso-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'
]
[dev-dependencies]
wasm-bindgen-test = "0.2"

View File

@ -0,0 +1,4 @@
# Enso Prelude
The Enso prelude is a library in the style of the Haskell prelude, pulling in a
number of useful foundational features for writing Rust code in the
[Enso](https://github.com/enso-org/enso) project.

View File

@ -0,0 +1,117 @@
use crate::*;
pub use enso_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;
}
// === Macros ===
#[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()
}
}
impl <$($bounds)*> From<&$($toks)*> for $($toks)* {
fn from(t:&$($toks)*) -> Self {
t.clone_ref()
}
}
};
($($toks:tt)*) => {
impl CloneRef for $($toks)* {
fn clone_ref(&self) -> Self {
self.clone()
}
}
impl From<&$($toks)*> for $($toks)* {
fn from(t:&$($toks)*) -> Self {
t.clone_ref()
}
}
};
}
#[macro_export]
macro_rules! impl_clone_ref_as_clone_no_from {
([$($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()
}
}
};
}
// === Prim Impls ===
impl_clone_ref_as_clone_no_from!(());
impl_clone_ref_as_clone_no_from!(f32);
impl_clone_ref_as_clone_no_from!(f64);
impl_clone_ref_as_clone_no_from!(i32);
impl_clone_ref_as_clone_no_from!(i64);
impl_clone_ref_as_clone_no_from!(usize);
impl_clone_ref_as_clone_no_from!([T] PhantomData<T>);
impl_clone_ref_as_clone_no_from!([T:?Sized] Rc<T>);
impl_clone_ref_as_clone_no_from!([T:?Sized] Weak<T>);
impl_clone_ref_as_clone_no_from!(wasm_bindgen::JsValue);
impl_clone_ref_as_clone_no_from!(web_sys::HtmlDivElement);
impl_clone_ref_as_clone_no_from!(web_sys::HtmlElement);
impl_clone_ref_as_clone_no_from!(web_sys::Performance);
impl_clone_ref_as_clone_no_from!(web_sys::WebGl2RenderingContext);
impl_clone_ref_as_clone_no_from!(web_sys::HtmlCanvasElement);
impl_clone_ref_as_clone_no_from!(web_sys::EventTarget);
// === Option ===
/// Trait for types that can be internally cloned using `CloneRef`, like `Option<&T>`.
#[allow(missing_docs)]
pub trait ClonedRef {
type Output;
fn cloned_ref(&self) -> Self::Output;
}
impl<T:CloneRef> ClonedRef for Option<&T> {
type Output = Option<T>;
fn cloned_ref(&self) -> Self::Output {
self.map(|t| t.clone_ref())
}
}
impl<T:CloneRef> ClonedRef for Option<&mut T> {
type Output = Option<T>;
fn cloned_ref(&self) -> Self::Output {
self.as_ref().map(|t| t.clone_ref())
}
}

View File

@ -0,0 +1,6 @@
//! 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;

View File

@ -0,0 +1,9 @@
//! 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::*;

View File

@ -0,0 +1,55 @@
//! 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
}
}
}

View File

@ -0,0 +1,107 @@
//! 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];

View File

@ -0,0 +1,143 @@
//! 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]));
}
}

View File

@ -0,0 +1,350 @@
//! 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)
}
}
// ==================
// === Result Ops ===
// ==================
/// Allows extracting the element from `Result<T,T>` for any `T`.
#[allow(missing_docs)]
pub trait ResultGet {
type Item;
/// Allows extracting the element from `Result<T,T>` for any `T`.
fn unwrap_both(self) -> Self::Item;
}
impl<T> ResultGet for Result<T,T> {
type Item = T;
fn unwrap_both(self) -> T {
match self {
Ok (t) => t,
Err (t) => t,
}
}
}

View File

@ -0,0 +1,173 @@
//! 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)* } }
};
}

View File

@ -0,0 +1,25 @@
//! 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); }
}
}

View File

@ -0,0 +1,94 @@
//! 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>;

View File

@ -0,0 +1,78 @@
//! 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;
}

View File

@ -0,0 +1,70 @@
//! 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;
pub use std::ops::RangeBounds;
pub use std::ops::RangeFrom;
pub use std::ops::RangeFull;
pub use std::ops::RangeInclusive;
pub use std::ops::RangeTo;
pub use std::ops::RangeToInclusive;
// === 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()
}

View File

@ -0,0 +1,247 @@
//! 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)
}
}
)*};
}

View File

@ -0,0 +1,80 @@
//! 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
}
}

View File

@ -0,0 +1,133 @@
//! 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] } }

View File

@ -0,0 +1,32 @@
[package]
name = "enso-shapely"
version = "0.1.0"
authors = ["Enso Team <enso-dev@enso.org>"]
edition = "2018"
description = "Automated typeclass derivation."
readme = "README.md"
homepage = "https://github.com/enso-org/enso/lib/rust/shapely/impl"
repository = "https://github.com/enso-org/enso"
license-file = "../../../../LICENSE"
keywords = ["typeclass", "deriving"]
categories = ["algorithms"]
publish = true
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = []
[dependencies]
enso-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 = { path = "../../enso-prelude" }
wasm-bindgen-test = "0.2"

View File

@ -0,0 +1,2 @@
# Shapely
This crate provides automatic derivation for useful type classes.

View File

@ -0,0 +1,45 @@
/// 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 }
};
}

View File

@ -0,0 +1,90 @@
//! Helper code meant to be used by the code generated through usage of macros
//! from `enso-shapely-macros` crate.
pub use enso_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);
}
}

View File

@ -0,0 +1,405 @@
// 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 enso_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());
}

View File

@ -0,0 +1,381 @@
/// 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)* }
};
}

View File

@ -0,0 +1,143 @@
//! 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),*}}
}
}

View File

@ -0,0 +1,174 @@
#![feature(generators)]
#![feature(type_alias_impl_trait)]
use enso_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());
}

View File

@ -0,0 +1,54 @@
// 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;

View File

@ -0,0 +1,39 @@
[package]
name = "enso-shapely-macros"
version = "0.1.0"
authors = ["Enso Team <enso-dev@enso.org>"]
edition = "2018"
description = "Automated typeclass derivation."
readme = "README.md"
homepage = "https://github.com/enso-org/enso/lib/rust/shapely/macros/"
repository = "https://github.com/enso-org/enso"
license-file = "../../../../LICENSE"
keywords = ["typeclass", "deriving", "macro"]
categories = ["algorithms"]
publish = true
[lib]
proc-macro = true
[features]
default = []
[dependencies]
enso-macro-utils = { version = "0.1.0" , path = "../../enso-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'
]
[dev-dependencies]
wasm-bindgen-test = "0.2"

View File

@ -0,0 +1,2 @@
# Shapely Macros
This crate provides macros for typeclass derivation.

View File

@ -0,0 +1,224 @@
use crate::prelude::*;
use enso_macro_utils::field_names;
use enso_macro_utils::identifier_sequence;
use enso_macro_utils::index_sequence;
use enso_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 = enso_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()
}

View File

@ -0,0 +1,449 @@
use crate::prelude::*;
use enso_macro_utils::fields_list;
use enso_macro_utils::field_ident_token;
use enso_macro_utils::type_depends_on;
use enso_macro_utils::type_matches;
use enso_macro_utils::ty_path_type_args;
use enso_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!(enso_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(enso-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();
// enso-shapely::EmptyIterator::new()
let empty_body = quote! { enso_shapely::EmptyIterator::new() };
// enso-shapely::GeneratingIterator(move || {
// yield &t.foo;
// })
// enso-shapely::GeneratingIterator(move || {
// yield &mut t.foo;
// })
let body = quote! {
enso_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> {
// enso-shapely::GeneratingIterator(move || {
// yield &t.foo;
// })
// }
// pub fn foo_iterator_mut<'t, T>
// (t: &'t mut Foo<T>) -> FooIteratorMut<'t, T> {
// enso-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),
// }

View File

@ -0,0 +1,98 @@
//! This crate defines a custom derive macro `Iterator`. Should not be used
//! directly, but only through `enso-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 enso_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)
}

View File

@ -0,0 +1,50 @@
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()
}

View File

@ -9,9 +9,9 @@ edition = "2018"
description = "A finite-automata-based lexing engine."
readme = "README.md"
homepage = "https://github.com/enso-org/enso"
homepage = "https://github.com/enso-org/enso/lib/rust/flexer"
repository = "https://github.com/enso-org/enso"
license-file = "../../LICENSE"
license-file = "../../../LICENSE"
keywords = ["lexer", "finite-automata"]
categories = ["parsing"]
@ -25,8 +25,10 @@ test = true
bench = true
[dependencies]
itertools = "0.8"
wasm-bindgen = "0.2"
enso-prelude = { path = "../enso-prelude", version = "0.1.0" }
itertools = "0.8"
unicode-segmentation = "1.6.0"
wasm-bindgen = "0.2"
[dev-dependencies]
wasm-bindgen-test = "0.2"

View File

@ -15,6 +15,7 @@ use std::ops::RangeInclusive;
/// When finite automata gets into invalid state the input sequence of symbols is rejected.
pub const INVALID:Id = Id {id:usize::max_value()};
// TODO [AA] Extract this. Turn it into using `char
/// Newtype wrapper for finite automata input symbol.
#[derive(Clone,Copy,Debug,PartialEq,Eq,PartialOrd,Ord,Hash)]
pub struct Symbol {
@ -22,6 +23,8 @@ pub struct Symbol {
pub val: u32
}
// TODO [AA] Define some constants on char
/// Newtype wrapper for finite automata state ID.
#[derive(Clone,Copy,Debug,PartialEq,Eq,PartialOrd,Ord,Hash)]
pub struct Id {

Some files were not shown because too many files have changed in this diff Show More