diff --git a/BUILDING_FROM_SOURCE.md b/BUILDING_FROM_SOURCE.md index 7bae697da1..d66b8e0648 100644 --- a/BUILDING_FROM_SOURCE.md +++ b/BUILDING_FROM_SOURCE.md @@ -1,90 +1,5 @@ # Building the Roc compiler from source - -## Installing LLVM, Zig, valgrind, and Python - -To build the compiler, you need these installed: - -* [Zig](https://ziglang.org/), see below for version -* `libxkbcommon` - macOS seems to have it already; on Ubuntu or Debian you can get it with `apt-get install libxkbcommon-dev` -* On Debian/Ubuntu `sudo apt-get install pkg-config` -* LLVM, see below for version - -To run the test suite (via `cargo test`), you additionally need to install: - -* [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781) -Alternatively, you can use `cargo test --no-fail-fast` or `cargo test -p specific_tests` to skip over the valgrind failures & tests. - -For debugging LLVM IR, we use [DebugIR](https://github.com/vaivaswatha/debugir). This dependency is only required to build with the `--debug` flag, and for normal developtment you should be fine without it. - -### libcxb libraries - -You may see an error like this during builds: - -``` -/usr/bin/ld: cannot find -lxcb-render -/usr/bin/ld: cannot find -lxcb-shape -/usr/bin/ld: cannot find -lxcb-xfixes -``` - -If so, you can fix it like so: - -``` -sudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev -``` - -### Zig -**version: 0.8.0** - -For any OS, you can use [`zigup`](https://github.com/marler8997/zigup) to manage zig installations. - -If you prefer a package manager, you can try the following: -- For MacOS, you can install with `brew install zig` -- For, Ubuntu, you can use Snap, you can install with `snap install zig --classic --beta` -- For other systems, checkout this [page](https://github.com/ziglang/zig/wiki/Install-Zig-from-a-Package-Manager) - -If you want to install it manually, you can also download Zig directly [here](https://ziglang.org/download/). Just make sure you download the right version, the bleeding edge master build is the first download link on this page. - -### LLVM -**version: 12.0.x** - -For macOS, you can install LLVM 12 using `brew install llvm@12` and then adding -`$(brew --prefix llvm@12)/bin` to your `PATH`. You can confirm this worked by -running `llc --version` - it should mention "LLVM version 12.0.0" at the top. -You may also need to manually specify a prefix env var like so: -``` -export LLVM_SYS_120_PREFIX=/usr/local/opt/llvm@12 -``` - -For Ubuntu and Debian: -``` -sudo apt -y install lsb-release software-properties-common gnupg -wget https://apt.llvm.org/llvm.sh -chmod +x llvm.sh -./llvm.sh 12 -``` - -If you use this script, you'll need to add `clang` and `llvm-as` to your `PATH`. -By default, the script installs them as `clang-12` and `llvm-as-12`, -respectively. You can address this with symlinks like so: - -``` -sudo ln -s /usr/bin/clang-12 /usr/bin/clang -``` -``` -sudo ln -s /usr/bin/llvm-as-12 /usr/bin/llvm-as -```` - -There are also alternative installation options at http://releases.llvm.org/download.html - -[Troubleshooting](#troubleshooting) - -### Building - -Use `cargo build` to build the whole project. -Use `cargo run help` to see all subcommands. -To use the `repl` subcommand, execute `cargo run repl`. - ## Using Nix ### Install @@ -168,6 +83,90 @@ Check the [nixGL repo](https://github.com/guibou/nixGL) for other graphics confi Create an issue if you run into problems not listed here. That will help us improve this document for everyone who reads it in the future! +## Manual Install + +To build the compiler, you need these installed: + +* [Zig](https://ziglang.org/), see below for version +* `libxkbcommon` - macOS seems to have it already; on Ubuntu or Debian you can get it with `apt-get install libxkbcommon-dev` +* On Debian/Ubuntu `sudo apt-get install pkg-config` +* LLVM, see below for version + +To run the test suite (via `cargo test`), you additionally need to install: + +* [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781) +Alternatively, you can use `cargo test --no-fail-fast` or `cargo test -p specific_tests` to skip over the valgrind failures & tests. + +For debugging LLVM IR, we use [DebugIR](https://github.com/vaivaswatha/debugir). This dependency is only required to build with the `--debug` flag, and for normal developtment you should be fine without it. + +### libcxb libraries + +You may see an error like this during builds: + +``` +/usr/bin/ld: cannot find -lxcb-render +/usr/bin/ld: cannot find -lxcb-shape +/usr/bin/ld: cannot find -lxcb-xfixes +``` + +If so, you can fix it like so: + +``` +sudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev +``` + +### Zig +**version: 0.8.0** + +For any OS, you can use [`zigup`](https://github.com/marler8997/zigup) to manage zig installations. + +If you prefer a package manager, you can try the following: +- For MacOS, you can install with `brew install zig` +- For, Ubuntu, you can use Snap, you can install with `snap install zig --classic --beta` +- For other systems, checkout this [page](https://github.com/ziglang/zig/wiki/Install-Zig-from-a-Package-Manager) + +If you want to install it manually, you can also download Zig directly [here](https://ziglang.org/download/). Just make sure you download the right version, the bleeding edge master build is the first download link on this page. + +### LLVM +**version: 12.0.x** + +For macOS, you can install LLVM 12 using `brew install llvm@12` and then adding +`$(brew --prefix llvm@12)/bin` to your `PATH`. You can confirm this worked by +running `llc --version` - it should mention "LLVM version 12.0.0" at the top. +You may also need to manually specify a prefix env var like so: +``` +export LLVM_SYS_120_PREFIX=/usr/local/opt/llvm@12 +``` + +For Ubuntu and Debian: +``` +sudo apt -y install lsb-release software-properties-common gnupg +wget https://apt.llvm.org/llvm.sh +chmod +x llvm.sh +./llvm.sh 12 +``` + +If you use this script, you'll need to add `clang` and `llvm-as` to your `PATH`. +By default, the script installs them as `clang-12` and `llvm-as-12`, +respectively. You can address this with symlinks like so: + +``` +sudo ln -s /usr/bin/clang-12 /usr/bin/clang +``` +``` +sudo ln -s /usr/bin/llvm-as-12 /usr/bin/llvm-as +```` + +There are also alternative installation options at http://releases.llvm.org/download.html + +[Troubleshooting](#troubleshooting) + +### Building + +Use `cargo build` to build the whole project. +Use `cargo run help` to see all subcommands. +To use the `repl` subcommand, execute `cargo run repl`. + ### LLVM installation on Linux For a current list of all dependency versions and their names in apt, see the Earthfile. diff --git a/LEGAL_DETAILS b/LEGAL_DETAILS index 3cb8fd3034..588ad49184 100644 --- a/LEGAL_DETAILS +++ b/LEGAL_DETAILS @@ -515,3 +515,24 @@ See the License for the specific language governing permissions and limitations under the License. =========================================================== + +* iced - https://github.com/iced-rs/iced + +Copyright 2019 Héctor Ramón, Iced contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/ast/src/constrain.rs b/ast/src/constrain.rs index f26eddd841..6c5af07eaf 100644 --- a/ast/src/constrain.rs +++ b/ast/src/constrain.rs @@ -1474,6 +1474,15 @@ pub fn constrain_pattern<'a>( )); } + CharacterLiteral(_) => { + state.constraints.push(Constraint::Pattern( + region, + PatternCategory::Character, + num_unsigned32(env.pool), + expected, + )); + } + RecordDestructure { whole_var, ext_var, @@ -1927,6 +1936,26 @@ fn _num_signed64(pool: &mut Pool) -> Type2 { ) } +#[inline(always)] +fn num_unsigned32(pool: &mut Pool) -> Type2 { + let alias_content = Type2::TagUnion( + PoolVec::new( + std::iter::once(( + TagName::Private(Symbol::NUM_UNSIGNED32), + PoolVec::empty(pool), + )), + pool, + ), + pool.add(Type2::EmptyTagUnion), + ); + + Type2::Alias( + Symbol::NUM_UNSIGNED32, + PoolVec::empty(pool), + pool.add(alias_content), + ) +} + #[inline(always)] fn _num_integer(pool: &mut Pool, range: TypeId) -> Type2 { let range_type = pool.get(range); diff --git a/ast/src/lang/core/pattern.rs b/ast/src/lang/core/pattern.rs index fdc4c09445..6687acd197 100644 --- a/ast/src/lang/core/pattern.rs +++ b/ast/src/lang/core/pattern.rs @@ -39,6 +39,7 @@ pub enum Pattern2 { IntLiteral(IntVal), // 16B FloatLiteral(FloatVal), // 16B StrLiteral(PoolStr), // 8B + CharacterLiteral(char), // 4B Underscore, // 0B GlobalTag { whole_var: Variable, // 4B @@ -249,6 +250,26 @@ pub fn to_pattern2<'a>( ptype => unsupported_pattern(env, ptype, region), }, + SingleQuote(string) => match pattern_type { + WhenBranch => { + let mut it = string.chars().peekable(); + if let Some(char) = it.next() { + if it.peek().is_none() { + Pattern2::CharacterLiteral(char) + } else { + // multiple chars is found + let problem = MalformedPatternProblem::MultipleCharsInSingleQuote; + malformed_pattern(env, problem, region) + } + } else { + // no characters found + let problem = MalformedPatternProblem::EmptySingleQuote; + malformed_pattern(env, problem, region) + } + } + ptype => unsupported_pattern(env, ptype, region), + }, + GlobalTag(name) => { // Canonicalize the tag's name. Pattern2::GlobalTag { @@ -506,6 +527,7 @@ pub fn symbols_from_pattern(pool: &Pool, initial: &Pattern2) -> Vec { | IntLiteral(_) | FloatLiteral(_) | StrLiteral(_) + | CharacterLiteral(_) | Underscore | MalformedPattern(_, _) | Shadowed { .. } @@ -566,6 +588,7 @@ pub fn symbols_and_variables_from_pattern( | IntLiteral(_) | FloatLiteral(_) | StrLiteral(_) + | CharacterLiteral(_) | Underscore | MalformedPattern(_, _) | Shadowed { .. } diff --git a/ast/src/lang/env.rs b/ast/src/lang/env.rs index 3f9e17e3d5..1b04f417d2 100644 --- a/ast/src/lang/env.rs +++ b/ast/src/lang/env.rs @@ -160,12 +160,17 @@ impl<'a> Env<'a> { }) } }, - None => { - panic!( - "Module {} exists, but is not recorded in dep_idents", - module_name - ) - } + None => Err(RuntimeError::ModuleNotImported { + module_name, + imported_modules: self + .dep_idents + .keys() + .filter_map(|module_id| self.module_ids.get_name(*module_id)) + .map(|module_name| module_name.as_ref().into()) + .collect(), + region, + module_exists: true, + }), } } } @@ -177,6 +182,7 @@ impl<'a> Env<'a> { .map(|string| string.as_ref().into()) .collect(), region, + module_exists: false, }), } } diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 8890ba8076..4b5d13d1c1 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -15,21 +15,24 @@ test = false bench = false [features] -default = ["target-aarch64", "target-x86_64", "target-wasm32", "editor"] +default = ["target-aarch64", "target-x86_64", "target-wasm32", "editor", "llvm"] wasm32-cli-run = ["target-wasm32", "run-wasm32"] i386-cli-run = ["target-x86"] +# TODO: change to roc_repl_cli/llvm once roc_repl can run without llvm. +llvm = ["roc_build/llvm", "roc_repl_cli"] + editor = ["roc_editor"] run-wasm32 = ["wasmer", "wasmer-wasi"] # Compiling for a different platform than the host can cause linker errors. -target-arm = ["roc_build/target-arm"] -target-aarch64 = ["roc_build/target-aarch64"] -target-x86 = ["roc_build/target-x86"] -target-x86_64 = ["roc_build/target-x86_64"] -target-wasm32 = ["roc_build/target-wasm32"] +target-arm = ["roc_build/target-arm", "roc_repl_cli/target-arm"] +target-aarch64 = ["roc_build/target-aarch64", "roc_repl_cli/target-aarch64"] +target-x86 = ["roc_build/target-x86", "roc_repl_cli/target-x86"] +target-x86_64 = ["roc_build/target-x86_64", "roc_repl_cli/target-x86_64"] +target-wasm32 = ["roc_build/target-wasm32", "roc_repl_cli/target-wasm32"] target-all = [ "target-aarch64", @@ -50,15 +53,15 @@ roc_module = { path = "../compiler/module" } roc_builtins = { path = "../compiler/builtins" } roc_mono = { path = "../compiler/mono" } roc_load = { path = "../compiler/load" } -roc_build = { path = "../compiler/build", default-features = false } +roc_build = { path = "../compiler/build" } roc_fmt = { path = "../compiler/fmt" } roc_target = { path = "../compiler/roc_target" } roc_reporting = { path = "../reporting" } roc_error_macros = { path = "../error_macros" } roc_editor = { path = "../editor", optional = true } roc_linker = { path = "../linker" } -roc_repl_cli = { path = "../repl_cli" } -clap = { version = "= 3.0.0-beta.5", default-features = false, features = ["std", "color", "suggestions"] } +roc_repl_cli = { path = "../repl_cli", optional = true } +clap = { version = "3.0.0-beta.5", default-features = false, features = ["std", "color", "suggestions"] } const_format = "0.2.22" bumpalo = { version = "3.8.0", features = ["collections"] } mimalloc = { version = "0.1.26", default-features = false } diff --git a/cli/src/format.rs b/cli/src/format.rs index 5504cf8e6d..ef2e853867 100644 --- a/cli/src/format.rs +++ b/cli/src/format.rs @@ -607,6 +607,7 @@ impl<'a> RemoveSpaces<'a> for Expr<'a> { Expr::PrecedenceConflict(a) => Expr::PrecedenceConflict(a), Expr::SpaceBefore(a, _) => a.remove_spaces(arena), Expr::SpaceAfter(a, _) => a.remove_spaces(arena), + Expr::SingleQuote(a) => Expr::Num(a), } } } @@ -649,6 +650,7 @@ impl<'a> RemoveSpaces<'a> for Pattern<'a> { } Pattern::SpaceBefore(a, _) => a.remove_spaces(arena), Pattern::SpaceAfter(a, _) => a.remove_spaces(arena), + Pattern::SingleQuote(a) => Pattern::NumLiteral(a), } } } diff --git a/cli/src/main.rs b/cli/src/main.rs index a90ca61554..f07ecdd943 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -63,10 +63,16 @@ fn main() -> io::Result<()> { } } Some((CMD_REPL, _)) => { - roc_repl_cli::main()?; + #[cfg(feature = "llvm")] + { + roc_repl_cli::main()?; - // Exit 0 if the repl exited normally - Ok(0) + // Exit 0 if the repl exited normally + Ok(0) + } + + #[cfg(not(feature = "llvm"))] + todo!("enable roc repl without llvm"); } Some((CMD_EDIT, matches)) => { match matches diff --git a/cli/tests/cli_run.rs b/cli/tests/cli_run.rs index ea5bd4f33d..9e7aee0d8b 100644 --- a/cli/tests/cli_run.rs +++ b/cli/tests/cli_run.rs @@ -13,7 +13,8 @@ extern crate indoc; mod cli_run { use cli_utils::helpers::{ example_file, examples_dir, extract_valgrind_errors, fixture_file, fixtures_dir, - known_bad_file, run_cmd, run_roc, run_with_valgrind, ValgrindError, ValgrindErrorXWhat, + known_bad_file, run_cmd, run_roc, run_with_valgrind, Out, ValgrindError, + ValgrindErrorXWhat, }; use roc_test_utils::assert_multiline_str_eq; use serial_test::serial; @@ -80,6 +81,17 @@ mod cli_run { } } + fn build_example(file: &Path, flags: &[&str]) -> Out { + let compile_out = run_roc(&[&["build", file.to_str().unwrap()], flags].concat()); + if !compile_out.stderr.is_empty() { + panic!("roc build had stderr: {}", compile_out.stderr); + } + + assert!(compile_out.status.success(), "bad status {:?}", compile_out); + + compile_out + } + fn check_output_with_stdin( file: &Path, stdin: &[&str], @@ -96,12 +108,7 @@ mod cli_run { all_flags.extend_from_slice(&["--valgrind"]); } - let compile_out = run_roc(&[&["build", file.to_str().unwrap()], &all_flags[..]].concat()); - if !compile_out.stderr.is_empty() { - panic!("roc build had stderr: {}", compile_out.stderr); - } - - assert!(compile_out.status.success(), "bad status {:?}", compile_out); + build_example(file, &all_flags[..]); let out = if use_valgrind && ALLOW_VALGRIND { let (valgrind_out, raw_xml) = if let Some(input_file) = input_file { @@ -238,6 +245,17 @@ mod cli_run { return; } } + "hello-gui" => { + // Since this one requires opening a window, we do `roc build` on it but don't run it. + if cfg!(target_os = "linux") { + // The surgical linker can successfully link this on Linux, but the legacy linker errors! + build_example(&file_name, &["--optimize", "--roc-linker"]); + } else { + build_example(&file_name, &["--optimize"]); + } + + return; + } _ => {} } @@ -354,6 +372,14 @@ mod cli_run { expected_ending:"55\n", use_valgrind: true, }, + gui:"gui" => Example { + filename: "Hello.roc", + executable_filename: "hello-gui", + stdin: &[], + input_file: None, + expected_ending: "", + use_valgrind: false, + }, quicksort:"quicksort" => Example { filename: "Quicksort.roc", executable_filename: "quicksort", diff --git a/cli_utils/Cargo.lock b/cli_utils/Cargo.lock index c385582180..c1fa0f03f4 100644 --- a/cli_utils/Cargo.lock +++ b/cli_utils/Cargo.lock @@ -897,6 +897,12 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" +[[package]] +name = "dunce" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541" + [[package]] name = "either" version = "1.6.1" @@ -2504,6 +2510,7 @@ dependencies = [ name = "roc_builtins" version = "0.1.0" dependencies = [ + "dunce", "roc_collections", "roc_module", "roc_region", @@ -2518,6 +2525,7 @@ dependencies = [ "bumpalo", "roc_builtins", "roc_collections", + "roc_error_macros", "roc_module", "roc_parse", "roc_problem", @@ -2587,6 +2595,7 @@ dependencies = [ "roc_builtins", "roc_can", "roc_collections", + "roc_error_macros", "roc_module", "roc_parse", "roc_region", @@ -2687,6 +2696,7 @@ dependencies = [ "roc_mono", "roc_problem", "roc_region", + "roc_reporting", "roc_solve", "roc_target", "roc_types", @@ -2760,6 +2770,7 @@ dependencies = [ "roc_can", "roc_collections", "roc_constrain", + "roc_error_macros", "roc_module", "roc_mono", "roc_parse", diff --git a/code_markup/src/lib.rs b/code_markup/src/lib.rs index 9e5d220855..1b140a9678 100644 --- a/code_markup/src/lib.rs +++ b/code_markup/src/lib.rs @@ -3,3 +3,4 @@ pub mod markup; pub mod markup_error; pub mod slow_pool; pub mod syntax_highlight; +pub mod underline_style; diff --git a/code_markup/src/markup/attribute.rs b/code_markup/src/markup/attribute.rs index 90b4801f18..58f57bc206 100644 --- a/code_markup/src/markup/attribute.rs +++ b/code_markup/src/markup/attribute.rs @@ -55,8 +55,13 @@ pub enum Attribute { HighlightStart { highlight_start: HighlightStart }, HighlightEnd { highlight_end: HighlightEnd }, - UnderlineStart { underline_start: UnderlineStart }, - UnderlineEnd { underline_end: UnderlineEnd }, + Underline { underline_spec: UnderlineSpec }, +} + +#[derive(Debug)] +pub enum UnderlineSpec { + Partial { start: usize, end: usize }, + Full, } #[derive(Debug, Default)] diff --git a/code_markup/src/underline_style.rs b/code_markup/src/underline_style.rs new file mode 100644 index 0000000000..4eb81ee73c --- /dev/null +++ b/code_markup/src/underline_style.rs @@ -0,0 +1,20 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use crate::colors::{from_hsb, RgbaTup}; + +#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug, Deserialize, Serialize)] +pub enum UnderlineStyle { + Error, + Warning, +} + +pub fn default_underline_color_map() -> HashMap { + let mut underline_colors = HashMap::new(); + + underline_colors.insert(UnderlineStyle::Error, from_hsb(0, 50, 75)); + underline_colors.insert(UnderlineStyle::Warning, from_hsb(60, 50, 75)); + + underline_colors +} diff --git a/compiler/build/Cargo.toml b/compiler/build/Cargo.toml index ab61cf2637..54872936b4 100644 --- a/compiler/build/Cargo.toml +++ b/compiler/build/Cargo.toml @@ -24,7 +24,7 @@ roc_gen_llvm = { path = "../gen_llvm", optional = true } roc_gen_wasm = { path = "../gen_wasm", optional = true } roc_gen_dev = { path = "../gen_dev", default-features = false } roc_reporting = { path = "../../reporting" } -roc_std = { path = "../../roc_std" } +roc_std = { path = "../../roc_std", default-features = false } bumpalo = { version = "3.8.0", features = ["collections"] } libloading = "0.7.1" tempfile = "3.2.0" @@ -35,7 +35,6 @@ target-lexicon = "0.12.2" serde_json = "1.0.69" [features] -default = ["llvm", "target-aarch64", "target-x86_64", "target-wasm32"] target-arm = [] target-aarch64 = ["roc_gen_dev/target-aarch64"] target-x86 = [] diff --git a/compiler/build/src/link.rs b/compiler/build/src/link.rs index 27ef1cc7ca..f569cae620 100644 --- a/compiler/build/src/link.rs +++ b/compiler/build/src/link.rs @@ -835,8 +835,6 @@ fn link_linux( let env_path = env::var("PATH").unwrap_or_else(|_| "".to_string()); - init_arch(target); - // NOTE: order of arguments to `ld` matters here! // The `-l` flags should go after the `.o` arguments @@ -1108,13 +1106,3 @@ fn validate_output(file_name: &str, cmd_name: &str, output: Output) { } } } - -#[cfg(feature = "llvm")] -fn init_arch(target: &Triple) { - crate::target::init_arch(target); -} - -#[cfg(not(feature = "llvm"))] -fn init_arch(_target: &Triple) { - panic!("Tried to initialize LLVM when crate was not built with `feature = \"llvm\"` enabled"); -} diff --git a/compiler/build/src/program.rs b/compiler/build/src/program.rs index 53b74ae8b1..8db3cbbb86 100644 --- a/compiler/build/src/program.rs +++ b/compiler/build/src/program.rs @@ -179,7 +179,7 @@ pub fn gen_from_mono_module( _emit_debug_info: bool, ) -> CodeGenTiming { match opt_level { - OptLevel::Optimize => { + OptLevel::Optimize | OptLevel::Size => { todo!("Return this error message in a better way: optimized builds not supported without llvm backend"); } OptLevel::Normal | OptLevel::Development => { diff --git a/compiler/can/src/annotation.rs b/compiler/can/src/annotation.rs index 8d3febe818..bcbb7aceed 100644 --- a/compiler/can/src/annotation.rs +++ b/compiler/can/src/annotation.rs @@ -130,7 +130,9 @@ fn make_apply_symbol( // it was imported but it doesn't expose this ident. env.problem(roc_problem::can::Problem::RuntimeError(problem)); - Err(Type::Erroneous(Problem::UnrecognizedIdent((*ident).into()))) + // A failed import should have already been reported through + // roc_can::env::Env::qualified_lookup's checks + Err(Type::Erroneous(Problem::SolvedTypeError)) } } } diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index 07a48d5580..fbb14fa846 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -854,6 +854,7 @@ fn pattern_to_vars_by_symbol( | IntLiteral(..) | FloatLiteral(..) | StrLiteral(_) + | SingleQuote(_) | Underscore | MalformedPattern(_, _) | UnsupportedPattern(_) diff --git a/compiler/can/src/env.rs b/compiler/can/src/env.rs index 46f627d7d9..e1216c42eb 100644 --- a/compiler/can/src/env.rs +++ b/compiler/can/src/env.rs @@ -124,12 +124,17 @@ impl<'a> Env<'a> { }) } }, - None => { - panic!( - "Module {} exists, but is not recorded in dep_idents", - module_name - ) - } + None => Err(RuntimeError::ModuleNotImported { + module_name, + imported_modules: self + .dep_idents + .keys() + .filter_map(|module_id| self.module_ids.get_name(*module_id)) + .map(|module_name| module_name.as_ref().into()) + .collect(), + region, + module_exists: true, + }), } } } @@ -141,6 +146,7 @@ impl<'a> Env<'a> { .map(|string| string.as_ref().into()) .collect(), region, + module_exists: false, }), } } diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index e61a153016..0912ea6988 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -73,6 +73,7 @@ pub enum Expr { Int(Variable, Variable, Box, IntValue, IntBound), Float(Variable, Variable, Box, f64, FloatBound), Str(Box), + SingleQuote(char), List { elem_var: Variable, loc_elems: Vec>, @@ -323,6 +324,28 @@ pub fn canonicalize_expr<'a>( } } ast::Expr::Str(literal) => flatten_str_literal(env, var_store, scope, literal), + + ast::Expr::SingleQuote(string) => { + let mut it = string.chars().peekable(); + if let Some(char) = it.next() { + if it.peek().is_none() { + (Expr::SingleQuote(char), Output::default()) + } else { + // multiple chars is found + let error = roc_problem::can::RuntimeError::MultipleCharsInSingleQuote(region); + let answer = Expr::RuntimeError(error); + + (answer, Output::default()) + } + } else { + // no characters found + let error = roc_problem::can::RuntimeError::EmptySingleQuote(region); + let answer = Expr::RuntimeError(error); + + (answer, Output::default()) + } + } + ast::Expr::List(loc_elems) => { if loc_elems.is_empty() { ( @@ -1267,6 +1290,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) -> | other @ Int(..) | other @ Float(..) | other @ Str { .. } + | other @ SingleQuote(_) | other @ RuntimeError(_) | other @ EmptyRecord | other @ Accessor { .. } diff --git a/compiler/can/src/module.rs b/compiler/can/src/module.rs index 39936e8d6e..df23b4ef42 100644 --- a/compiler/can/src/module.rs +++ b/compiler/can/src/module.rs @@ -572,6 +572,7 @@ fn fix_values_captured_in_closure_pattern( | IntLiteral(..) | FloatLiteral(..) | StrLiteral(_) + | SingleQuote(_) | Underscore | Shadowed(..) | MalformedPattern(_, _) @@ -629,6 +630,7 @@ fn fix_values_captured_in_closure_expr( | Int(..) | Float(..) | Str(_) + | SingleQuote(_) | Var(_) | EmptyRecord | RuntimeError(_) diff --git a/compiler/can/src/operator.rs b/compiler/can/src/operator.rs index be59f5ce9c..0c8d00177d 100644 --- a/compiler/can/src/operator.rs +++ b/compiler/can/src/operator.rs @@ -126,6 +126,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc>) -> &'a Loc | Num(..) | NonBase10Int { .. } | Str(_) + | SingleQuote(_) | AccessorFunction(_) | Var { .. } | Underscore { .. } diff --git a/compiler/can/src/pattern.rs b/compiler/can/src/pattern.rs index e167a612d3..a7187bb764 100644 --- a/compiler/can/src/pattern.rs +++ b/compiler/can/src/pattern.rs @@ -39,6 +39,7 @@ pub enum Pattern { IntLiteral(Variable, Variable, Box, IntValue, IntBound), FloatLiteral(Variable, Variable, Box, f64, FloatBound), StrLiteral(Box), + SingleQuote(char), Underscore, // Runtime Exceptions @@ -108,6 +109,7 @@ pub fn symbols_from_pattern_help(pattern: &Pattern, symbols: &mut Vec) { | IntLiteral(..) | FloatLiteral(..) | StrLiteral(_) + | SingleQuote(_) | Underscore | MalformedPattern(_, _) | UnsupportedPattern(_) @@ -309,6 +311,23 @@ pub fn canonicalize_pattern<'a>( ptype => unsupported_pattern(env, ptype, region), }, + SingleQuote(string) => { + let mut it = string.chars().peekable(); + if let Some(char) = it.next() { + if it.peek().is_none() { + Pattern::SingleQuote(char) + } else { + // multiple chars is found + let problem = MalformedPatternProblem::MultipleCharsInSingleQuote; + malformed_pattern(env, problem, region) + } + } else { + // no characters found + let problem = MalformedPatternProblem::EmptySingleQuote; + malformed_pattern(env, problem, region) + } + } + SpaceBefore(sub_pattern, _) | SpaceAfter(sub_pattern, _) => { return canonicalize_pattern(env, var_store, scope, pattern_type, sub_pattern, region) } @@ -560,6 +579,7 @@ fn add_bindings_from_patterns( | IntLiteral(..) | FloatLiteral(..) | StrLiteral(_) + | SingleQuote(_) | Underscore | MalformedPattern(_, _) | UnsupportedPattern(_) diff --git a/compiler/constrain/src/builtins.rs b/compiler/constrain/src/builtins.rs index 8812d2ec85..cf1a907845 100644 --- a/compiler/constrain/src/builtins.rs +++ b/compiler/constrain/src/builtins.rs @@ -193,6 +193,21 @@ pub fn num_floatingpoint(range: Type) -> Type { ) } +#[inline(always)] +pub fn num_u32() -> Type { + builtin_alias(Symbol::NUM_U32, vec![], Box::new(num_int(num_unsigned32()))) +} + +#[inline(always)] +fn num_unsigned32() -> Type { + let alias_content = Type::TagUnion( + vec![(TagName::Private(Symbol::NUM_AT_UNSIGNED32), vec![])], + Box::new(Type::EmptyTagUnion), + ); + + builtin_alias(Symbol::NUM_UNSIGNED32, vec![], Box::new(alias_content)) +} + #[inline(always)] pub fn num_binary64() -> Type { let alias_content = Type::TagUnion( diff --git a/compiler/constrain/src/expr.rs b/compiler/constrain/src/expr.rs index c44feb1c3a..dd93c7d535 100644 --- a/compiler/constrain/src/expr.rs +++ b/compiler/constrain/src/expr.rs @@ -1,5 +1,5 @@ use crate::builtins::{ - empty_list_type, float_literal, int_literal, list_type, num_literal, str_type, + empty_list_type, float_literal, int_literal, list_type, num_literal, num_u32, str_type, }; use crate::pattern::{constrain_pattern, PatternState}; use roc_can::annotation::IntroducedVariables; @@ -213,6 +213,7 @@ pub fn constrain_expr( exists(vars, And(cons)) } Str(_) => Eq(str_type(), expected, Category::Str, region), + SingleQuote(_) => Eq(num_u32(), expected, Category::Character, region), List { elem_var, loc_elems, diff --git a/compiler/constrain/src/pattern.rs b/compiler/constrain/src/pattern.rs index b8caa521c9..7308b261a0 100644 --- a/compiler/constrain/src/pattern.rs +++ b/compiler/constrain/src/pattern.rs @@ -60,6 +60,7 @@ fn headers_from_annotation_help( | NumLiteral(..) | IntLiteral(..) | FloatLiteral(..) + | SingleQuote(_) | StrLiteral(_) => true, RecordDestructure { destructs, .. } => match annotation.value.shallow_dealias() { @@ -252,6 +253,15 @@ pub fn constrain_pattern( )); } + SingleQuote(_) => { + state.constraints.push(Constraint::Pattern( + region, + PatternCategory::Character, + builtins::num_u32(), + expected, + )); + } + RecordDestructure { whole_var, ext_var, diff --git a/compiler/fmt/src/collection.rs b/compiler/fmt/src/collection.rs index 5765f0f4d1..9e54b327cf 100644 --- a/compiler/fmt/src/collection.rs +++ b/compiler/fmt/src/collection.rs @@ -49,7 +49,6 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable>( ); buf.newline(); buf.indent(braces_indent); - buf.push(end); } else { // is_multiline == false // there is no comment to add @@ -67,7 +66,7 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable>( if !items.is_empty() { buf.spaces(1); } - - buf.push(end); } + + buf.push(end); } diff --git a/compiler/fmt/src/expr.rs b/compiler/fmt/src/expr.rs index fa1dc7eb1b..72a41531ff 100644 --- a/compiler/fmt/src/expr.rs +++ b/compiler/fmt/src/expr.rs @@ -30,6 +30,7 @@ impl<'a> Formattable for Expr<'a> { Float(..) | Num(..) | NonBase10Int { .. } + | SingleQuote(_) | Access(_, _) | AccessorFunction(_) | Var { .. } @@ -209,6 +210,11 @@ impl<'a> Formattable for Expr<'a> { buf.indent(indent); buf.push_str(string) } + SingleQuote(string) => { + buf.push('\''); + buf.push_str(string); + buf.push('\''); + } &NonBase10Int { base, string, diff --git a/compiler/fmt/src/pattern.rs b/compiler/fmt/src/pattern.rs index 61e968c2f6..c903ad9596 100644 --- a/compiler/fmt/src/pattern.rs +++ b/compiler/fmt/src/pattern.rs @@ -36,6 +36,7 @@ impl<'a> Formattable for Pattern<'a> { | Pattern::NonBase10Literal { .. } | Pattern::FloatLiteral(..) | Pattern::StrLiteral(_) + | Pattern::SingleQuote(_) | Pattern::Underscore(_) | Pattern::Malformed(_) | Pattern::MalformedIdent(_, _) @@ -147,6 +148,11 @@ impl<'a> Formattable for Pattern<'a> { StrLiteral(literal) => { todo!("Format string literal: {:?}", literal); } + SingleQuote(string) => { + buf.push('\''); + buf.push_str(string); + buf.push('\''); + } Underscore(name) => { buf.indent(indent); buf.push('_'); diff --git a/compiler/gen_dev/Cargo.toml b/compiler/gen_dev/Cargo.toml index ca81c78e67..0b5a08fe0d 100644 --- a/compiler/gen_dev/Cargo.toml +++ b/compiler/gen_dev/Cargo.toml @@ -30,7 +30,7 @@ packed_struct = "0.10.0" [dev-dependencies] roc_can = { path = "../can" } roc_parse = { path = "../parse" } -roc_std = { path = "../../roc_std" } +roc_std = { path = "../../roc_std", default-features = false } bumpalo = { version = "3.8.0", features = ["collections"] } [features] diff --git a/compiler/gen_llvm/Cargo.toml b/compiler/gen_llvm/Cargo.toml index e87ed1c434..96dfaaf58e 100644 --- a/compiler/gen_llvm/Cargo.toml +++ b/compiler/gen_llvm/Cargo.toml @@ -13,7 +13,7 @@ roc_builtins = { path = "../builtins" } roc_error_macros = { path = "../../error_macros" } roc_mono = { path = "../mono" } roc_target = { path = "../roc_target" } -roc_std = { path = "../../roc_std" } +roc_std = { path = "../../roc_std", default-features = false } morphic_lib = { path = "../../vendor/morphic_lib" } bumpalo = { version = "3.8.0", features = ["collections"] } inkwell = { path = "../../vendor/inkwell" } diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index e6eef0faa5..d3be9df353 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -3619,7 +3619,12 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>( _ => (¶ms[..], ¶m_types[..]), }; - debug_assert_eq!(params.len(), param_types.len()); + debug_assert!( + params.len() == param_types.len(), + "when exposing a function to the host, params.len() was {}, but param_types.len() was {}", + params.len(), + param_types.len() + ); let it = params.iter().zip(param_types).map(|(arg, fastcc_type)| { let arg_type = arg.get_type(); diff --git a/compiler/gen_wasm/Cargo.toml b/compiler/gen_wasm/Cargo.toml index b2223ee48a..ccdb6b2768 100644 --- a/compiler/gen_wasm/Cargo.toml +++ b/compiler/gen_wasm/Cargo.toml @@ -12,5 +12,5 @@ roc_collections = { path = "../collections" } roc_module = { path = "../module" } roc_mono = { path = "../mono" } roc_target = { path = "../roc_target" } -roc_std = { path = "../../roc_std" } +roc_std = { path = "../../roc_std", default-features = false } roc_error_macros = { path = "../../error_macros" } diff --git a/compiler/ident/src/lib.rs b/compiler/ident/src/lib.rs index e152271bc4..d611241926 100644 --- a/compiler/ident/src/lib.rs +++ b/compiler/ident/src/lib.rs @@ -3,7 +3,8 @@ use core::cmp::Ordering; use core::convert::From; use core::{fmt, mem, ptr, slice}; -use std::alloc::{GlobalAlloc, Layout, System}; +use std::alloc::{alloc, dealloc, Layout}; +use std::os::raw::c_char; /// A string which can store identifiers using the small string optimization. /// It relies on the invariant that it cannot store null characters to store @@ -66,19 +67,7 @@ impl IdentStr { } pub fn get(&self, index: usize) -> Option<&u8> { - if index < self.len() { - Some(unsafe { - let raw = if self.is_small_str() { - self.get_small_str_ptr().add(index) - } else { - self.elements.add(index) - }; - - &*raw - }) - } else { - None - } + self.as_bytes().get(index) } pub fn get_bytes(&self) -> *const u8 { @@ -93,59 +82,38 @@ impl IdentStr { (self as *const IdentStr).cast() } - fn from_slice(slice: &[u8]) -> Self { + fn from_str(str: &str) -> Self { + let slice = str.as_bytes(); let len = slice.len(); match len.cmp(&mem::size_of::()) { Ordering::Less => { - // This fits in a small string, but needs its length recorded - let mut answer_bytes: [u8; mem::size_of::()] = unsafe { - mem::transmute::()]>(Self::default()) - }; + let mut bytes = [0; mem::size_of::()]; - // Copy the bytes from the slice into the answer - let dest_slice = - unsafe { slice::from_raw_parts_mut(&mut answer_bytes as *mut u8, len) }; - - dest_slice.copy_from_slice(slice); - - let mut answer: Self = - unsafe { mem::transmute::<[u8; mem::size_of::()], Self>(answer_bytes) }; + // Copy the bytes from the slice into bytes. + bytes[..len].copy_from_slice(slice); // Write length and small string bit to last byte of length. - { - let mut bytes = answer.length.to_ne_bytes(); + bytes[mem::size_of::() * 2 - 1] = u8::MAX - len as u8; - bytes[mem::size_of::() - 1] = u8::MAX - len as u8; - - answer.length = usize::from_ne_bytes(bytes); - } - - answer + unsafe { mem::transmute::<[u8; mem::size_of::()], Self>(bytes) } } Ordering::Equal => { // This fits in a small string, and is exactly long enough to // take up the entire available struct - let mut answer_bytes: [u8; mem::size_of::()] = unsafe { - mem::transmute::()]>(Self::default()) - }; + let mut bytes = [0; mem::size_of::()]; // Copy the bytes from the slice into the answer - let dest_slice = unsafe { - slice::from_raw_parts_mut(&mut answer_bytes as *mut u8, mem::size_of::()) - }; + bytes.copy_from_slice(slice); - dest_slice.copy_from_slice(slice); - - unsafe { mem::transmute::<[u8; mem::size_of::()], Self>(answer_bytes) } + unsafe { mem::transmute::<[u8; mem::size_of::()], Self>(bytes) } } Ordering::Greater => { // This needs a big string + let align = mem::align_of::(); let elements = unsafe { - let align = mem::align_of::(); let layout = Layout::from_size_align_unchecked(len, align); - - System.alloc(layout) + alloc(layout) }; // Turn the new elements into a slice, and copy the existing @@ -167,7 +135,9 @@ impl IdentStr { pub fn as_slice(&self) -> &[u8] { use core::slice::from_raw_parts; - if self.is_small_str() { + if self.is_empty() { + &[] + } else if self.is_small_str() { unsafe { from_raw_parts(self.get_small_str_ptr(), self.len()) } } else { unsafe { from_raw_parts(self.elements, self.length) } @@ -186,15 +156,12 @@ impl IdentStr { /// # Safety /// This assumes the given buffer has enough space, so make sure you only /// pass in a pointer to an allocation that's at least as long as this Str! - pub unsafe fn write_c_str(&self, buf: *mut char) { - if self.is_small_str() { - ptr::copy_nonoverlapping(self.get_small_str_ptr(), buf as *mut u8, self.len()); - } else { - ptr::copy_nonoverlapping(self.elements, buf as *mut u8, self.len()); - } + pub unsafe fn write_c_str(&self, buf: *mut c_char) { + let bytes = self.as_bytes(); + ptr::copy_nonoverlapping(bytes.as_ptr().cast(), buf, bytes.len()); // null-terminate - *(buf.add(self.len())) = '\0'; + *buf.add(self.len()) = 0; } } @@ -217,13 +184,13 @@ impl std::ops::Deref for IdentStr { impl From<&str> for IdentStr { fn from(str: &str) -> Self { - Self::from_slice(str.as_bytes()) + Self::from_str(str) } } impl From for IdentStr { fn from(str: String) -> Self { - Self::from_slice(str.as_bytes()) + Self::from_str(&str) } } @@ -279,44 +246,17 @@ impl std::hash::Hash for IdentStr { impl Clone for IdentStr { fn clone(&self) -> Self { - if self.is_small_str() || self.is_empty() { - Self { - elements: self.elements, - length: self.length, - } - } else { - let capacity_size = core::mem::size_of::(); - let copy_length = self.length + capacity_size; - let elements = unsafe { - let align = mem::align_of::(); - let layout = Layout::from_size_align_unchecked(copy_length, align); - let raw_ptr = System.alloc(layout); - - let dest_slice = slice::from_raw_parts_mut(raw_ptr, copy_length); - let src_ptr = self.elements as *mut u8; - let src_slice = slice::from_raw_parts(src_ptr, copy_length); - - dest_slice.copy_from_slice(src_slice); - - raw_ptr as *mut u8 - }; - - Self { - elements, - length: self.length, - } - } + Self::from_str(self.as_str()) } } impl Drop for IdentStr { fn drop(&mut self) { if !self.is_empty() && !self.is_small_str() { + let align = mem::align_of::(); unsafe { - let align = mem::align_of::(); let layout = Layout::from_size_align_unchecked(self.length, align); - - System.dealloc(self.elements as *mut _, layout); + dealloc(self.elements as *mut _, layout); } } } diff --git a/compiler/load/Cargo.toml b/compiler/load/Cargo.toml index 081a055f6d..3945650771 100644 --- a/compiler/load/Cargo.toml +++ b/compiler/load/Cargo.toml @@ -24,7 +24,7 @@ roc_reporting = { path = "../../reporting" } morphic_lib = { path = "../../vendor/morphic_lib" } ven_pretty = { path = "../../vendor/pretty" } bumpalo = { version = "3.8.0", features = ["collections"] } -parking_lot = { version = "0.11.2" } +parking_lot = "0.11.2" crossbeam = "0.8.1" num_cpus = "1.13.0" diff --git a/compiler/mono/Cargo.toml b/compiler/mono/Cargo.toml index 5bdf3723fa..dd07c5f107 100644 --- a/compiler/mono/Cargo.toml +++ b/compiler/mono/Cargo.toml @@ -13,7 +13,7 @@ roc_types = { path = "../types" } roc_can = { path = "../can" } roc_unify = { path = "../unify" } roc_solve = { path = "../solve" } -roc_std = { path = "../../roc_std" } +roc_std = { path = "../../roc_std", default-features = false } roc_problem = { path = "../problem" } roc_builtins = { path = "../builtins" } roc_target = { path = "../roc_target" } diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 3aed213fd3..801a7c0c51 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -2040,8 +2040,11 @@ fn pattern_to_when<'a>( } UnwrappedOpaque { .. } => todo_opaques!(), - - IntLiteral(..) | NumLiteral(..) | FloatLiteral(..) | StrLiteral(_) => { + IntLiteral(..) + | NumLiteral(..) + | FloatLiteral(..) + | StrLiteral(..) + | roc_can::pattern::Pattern::SingleQuote(..) => { // These patters are refutable, and thus should never occur outside a `when` expression // They should have been replaced with `UnsupportedPattern` during canonicalization unreachable!("refutable pattern {:?} where irrefutable pattern is expected. This should never happen!", pattern.value) @@ -3147,6 +3150,13 @@ pub fn with_hole<'a>( hole, ), + SingleQuote(character) => Stmt::Let( + assigned, + Expr::Literal(Literal::Int(character as _)), + Layout::int_width(IntWidth::I32), + hole, + ), + Num(var, num_str, num, _bound) => { // first figure out what kind of number this is match num_argument_to_int_or_float(env.subs, env.target_info, var, false) { @@ -7226,7 +7236,8 @@ fn call_by_name_help<'a>( } else { debug_assert!( !field_symbols.is_empty(), - "should be in the list of imported_module_thunks" + "{} should be in the list of imported_module_thunks", + proc_name ); debug_assert_eq!( @@ -7745,6 +7756,7 @@ fn from_can_pattern_help<'a>( } } StrLiteral(v) => Ok(Pattern::StrLiteral(v.clone())), + SingleQuote(c) => Ok(Pattern::IntLiteral(*c as _, IntWidth::I32)), Shadowed(region, ident, _new_symbol) => Err(RuntimeError::Shadowing { original_region: *region, shadow: ident.clone(), diff --git a/compiler/parse/Cargo.toml b/compiler/parse/Cargo.toml index b1a4e86200..33954d8d95 100644 --- a/compiler/parse/Cargo.toml +++ b/compiler/parse/Cargo.toml @@ -16,7 +16,7 @@ bumpalo = { version = "3.8.0", features = ["collections"] } encode_unicode = "0.3.6" [dev-dependencies] -criterion = { version = "0.3", features = ["html_reports"] } +criterion = { version = "0.3.5", features = ["html_reports"] } pretty_assertions = "1.0.0" indoc = "1.0.3" quickcheck = "1.0.3" diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 43405d158b..6ca0c1cf5f 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -152,6 +152,8 @@ pub enum Expr<'a> { Access(&'a Expr<'a>, &'a str), /// e.g. `.foo` AccessorFunction(&'a str), + /// eg 'b' + SingleQuote(&'a str), // Collection Literals List(Collection<'a, &'a Loc>>), @@ -462,6 +464,7 @@ pub enum Pattern<'a> { FloatLiteral(&'a str), StrLiteral(StrLiteral<'a>), Underscore(&'a str), + SingleQuote(&'a str), // Space SpaceBefore(&'a Pattern<'a>, &'a [CommentOrNewline<'a>]), diff --git a/compiler/parse/src/expr.rs b/compiler/parse/src/expr.rs index 94d40c0a1b..4de9f94875 100644 --- a/compiler/parse/src/expr.rs +++ b/compiler/parse/src/expr.rs @@ -195,6 +195,7 @@ fn parse_loc_term_or_underscore<'a>( one_of!( loc_expr_in_parens_etc_help(min_indent), loc!(specialize(EExpr::Str, string_literal_help())), + loc!(specialize(EExpr::SingleQuote, single_quote_literal_help())), loc!(specialize(EExpr::Number, positive_number_literal_help())), loc!(specialize(EExpr::Lambda, closure_help(min_indent, options))), loc!(underscore_expression()), @@ -217,6 +218,7 @@ fn parse_loc_term<'a>( one_of!( loc_expr_in_parens_etc_help(min_indent), loc!(specialize(EExpr::Str, string_literal_help())), + loc!(specialize(EExpr::SingleQuote, single_quote_literal_help())), loc!(specialize(EExpr::Number, positive_number_literal_help())), loc!(specialize(EExpr::Lambda, closure_help(min_indent, options))), loc!(record_literal_help(min_indent)), @@ -1534,6 +1536,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result Err(()), Expr::Str(string) => Ok(Pattern::StrLiteral(*string)), + Expr::SingleQuote(string) => Ok(Pattern::SingleQuote(*string)), Expr::MalformedIdent(string, _problem) => Ok(Pattern::Malformed(string)), } } @@ -2352,6 +2355,13 @@ fn string_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EString<'a>> { map!(crate::string_literal::parse(), Expr::Str) } +fn single_quote_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EString<'a>> { + map!( + crate::string_literal::parse_single_quote(), + Expr::SingleQuote + ) +} + fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> { map!( crate::number_literal::positive_number_literal(), diff --git a/compiler/parse/src/parser.rs b/compiler/parse/src/parser.rs index d29b62f85b..130b382636 100644 --- a/compiler/parse/src/parser.rs +++ b/compiler/parse/src/parser.rs @@ -355,6 +355,7 @@ pub enum EExpr<'a> { InParens(EInParens<'a>, Position), Record(ERecord<'a>, Position), Str(EString<'a>, Position), + SingleQuote(EString<'a>, Position), Number(ENumber, Position), List(EList<'a>, Position), diff --git a/compiler/parse/src/pattern.rs b/compiler/parse/src/pattern.rs index 53e26fc3c2..dd99a1be43 100644 --- a/compiler/parse/src/pattern.rs +++ b/compiler/parse/src/pattern.rs @@ -61,6 +61,7 @@ pub fn loc_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Loc> )), loc!(number_pattern_help()), loc!(string_pattern_help()), + loc!(single_quote_pattern_help()), ) } @@ -108,6 +109,7 @@ fn loc_parse_tag_pattern_arg<'a>( crate::pattern::record_pattern_help(min_indent) )), loc!(string_pattern_help()), + loc!(single_quote_pattern_help()), loc!(number_pattern_help()) ) .parse(arena, state) @@ -159,6 +161,16 @@ fn string_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> { ) } +fn single_quote_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> { + specialize( + |_, pos| EPattern::Start(pos), + map!( + crate::string_literal::parse_single_quote(), + Pattern::SingleQuote + ), + ) +} + fn loc_ident_pattern_help<'a>( min_indent: u32, can_have_arguments: bool, diff --git a/compiler/parse/src/string_literal.rs b/compiler/parse/src/string_literal.rs index cf2b4b5674..4d77dc523f 100644 --- a/compiler/parse/src/string_literal.rs +++ b/compiler/parse/src/string_literal.rs @@ -35,6 +35,100 @@ macro_rules! advance_state { }; } +pub fn parse_single_quote<'a>() -> impl Parser<'a, &'a str, EString<'a>> { + move |arena: &'a Bump, mut state: State<'a>| { + if state.bytes().starts_with(b"\'") { + // we will be parsing a single-quote-string + } else { + return Err((NoProgress, EString::Open(state.pos()), state)); + } + + // early return did not hit, just advance one byte + state = advance_state!(state, 1)?; + + // Handle back slaches in byte literal + // - starts with a backslash and used as an escape character. ex: '\n', '\t' + // - single quote floating (un closed single quote) should be an error + match state.bytes().first() { + Some(b'\\') => { + state = advance_state!(state, 1)?; + match state.bytes().first() { + Some(&ch) => { + state = advance_state!(state, 1)?; + if (ch == b'n' || ch == b'r' || ch == b't' || ch == b'\'' || ch == b'\\') + && (state.bytes().first() == Some(&b'\'')) + { + state = advance_state!(state, 1)?; + let test = match ch { + b'n' => '\n', + b't' => '\t', + b'r' => '\r', + // since we checked the current char between the single quotes we + // know they are valid UTF-8, allowing us to use 'from_u32_unchecked' + _ => unsafe { char::from_u32_unchecked(ch as u32) }, + }; + + return Ok((MadeProgress, &*arena.alloc_str(&test.to_string()), state)); + } + // invalid error, backslah escaping something we do not recognize + return Err((NoProgress, EString::CodePtEnd(state.pos()), state)); + } + None => { + // no close quote found + return Err((NoProgress, EString::CodePtEnd(state.pos()), state)); + } + } + } + Some(_) => { + // do nothing for other characters, handled below + } + None => return Err((NoProgress, EString::CodePtEnd(state.pos()), state)), + } + + let mut bytes = state.bytes().iter(); + let mut end_index = 1; + + // Copy paste problem in mono + + loop { + match bytes.next() { + Some(b'\'') => { + break; + } + Some(_) => end_index += 1, + None => { + return Err((NoProgress, EString::Open(state.pos()), state)); + } + } + } + + if end_index == 1 { + // no progress was made + // this case is a double single quote, ex: '' + // not supporting empty single quotes + return Err((NoProgress, EString::Open(state.pos()), state)); + } + + if end_index > (std::mem::size_of::() + 1) { + // bad case: too big to fit into u32 + return Err((NoProgress, EString::Open(state.pos()), state)); + } + + // happy case -> we have some bytes that will fit into a u32 + // ending up w/ a slice of bytes that we want to convert into an integer + let raw_bytes = &state.bytes()[0..end_index - 1]; + + state = advance_state!(state, end_index)?; + match std::str::from_utf8(raw_bytes) { + Ok(string) => Ok((MadeProgress, string, state)), + Err(_) => { + // invalid UTF-8 + return Err((NoProgress, EString::CodePtEnd(state.pos()), state)); + } + } + } +} + pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> { use StrLiteral::*; diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 7af4ab53fc..8b60876c94 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -507,19 +507,28 @@ mod test_parse { } #[quickcheck] - fn all_f64_values_parse(num: f64) { - let string = num.to_string(); - if string.contains('.') { - assert_parses_to(&string, Float(&string)); - } else if num.is_nan() { - assert_parses_to(&string, Expr::GlobalTag(&string)); - } else if num.is_finite() { - // These are whole numbers. Add the `.0` back to make float. - let float_string = format!("{}.0", string); - assert_parses_to(&float_string, Float(&float_string)); + fn all_f64_values_parse(mut num: f64) { + // NaN, Infinity, -Infinity (these would all parse as tags in Roc) + if !num.is_finite() { + num = 0.0; } + + // These can potentially be whole numbers. `Display` omits the decimal point for those, + // causing them to no longer be parsed as fractional numbers by Roc. + // Using `Debug` instead of `Display` ensures they always have a decimal point. + let float_string = format!("{:?}", num); + + assert_parses_to(float_string.as_str(), Float(float_string.as_str())); } + // SINGLE QUOTE LITERAL + #[test] + fn single_quote() { + assert_parses_to("'b'", Expr::SingleQuote("b")); + } + + // RECORD LITERALS + // #[test] // fn type_signature_def() { // let arena = Bump::new(); diff --git a/compiler/problem/src/can.rs b/compiler/problem/src/can.rs index 55a26469b0..9eeac0af8d 100644 --- a/compiler/problem/src/can.rs +++ b/compiler/problem/src/can.rs @@ -171,10 +171,37 @@ pub enum RuntimeError { region: Region, exposed_values: Vec, }, + /// A module was referenced, but hasn't been imported anywhere in the program + /// + /// An example would be: + /// ```roc + /// app "hello" + /// packages { pf: "platform" } + /// imports [ pf.Stdout] + /// provides [ main ] to pf + /// + /// main : Task.Task {} [] // Task isn't imported! + /// main = Stdout.line "I'm a Roc application!" + /// ``` ModuleNotImported { + /// The name of the module that was referenced module_name: ModuleName, + /// A list of modules which *have* been imported imported_modules: MutSet>, + /// Where the problem occurred region: Region, + /// Whether or not the module exists at all + /// + /// This is used to suggest that the user import the module, as opposed to fix a + /// typo in the spelling. For example, if the user typed `Task`, and the platform + /// exposes a `Task` module that hasn't been imported, we can sugguest that they + /// add the import statement. + /// + /// On the other hand, if the user typed `Tesk`, they might want to check their + /// spelling. + /// + /// If unsure, this should be set to `false` + module_exists: bool, }, InvalidPrecedence(PrecedenceProblem, Region), MalformedIdentifier(Box, roc_parse::ident::BadIdent, Region), @@ -203,6 +230,11 @@ pub enum RuntimeError { VoidValue, ExposedButNotDefined(Symbol), + + /// where '' + EmptySingleQuote(Region), + /// where 'aa' + MultipleCharsInSingleQuote(Region), } #[derive(Clone, Copy, Debug, PartialEq)] @@ -213,4 +245,6 @@ pub enum MalformedPatternProblem { Unknown, QualifiedIdentifier, BadIdent(roc_parse::ident::BadIdent), + EmptySingleQuote, + MultipleCharsInSingleQuote, } diff --git a/compiler/test_gen/Cargo.toml b/compiler/test_gen/Cargo.toml index 67421a073d..203b669d48 100644 --- a/compiler/test_gen/Cargo.toml +++ b/compiler/test_gen/Cargo.toml @@ -30,7 +30,7 @@ roc_reporting = { path = "../../reporting" } roc_load = { path = "../load" } roc_can = { path = "../can" } roc_parse = { path = "../parse" } -roc_build = { path = "../build" } +roc_build = { path = "../build", features = ["target-aarch64", "target-x86_64", "target-wasm32"] } roc_target = { path = "../roc_target" } roc_std = { path = "../../roc_std" } bumpalo = { version = "3.8.0", features = ["collections"] } @@ -52,7 +52,7 @@ wasmer = { version = "2.0.0", default-features = false, features = ["default-cra [features] default = ["gen-llvm"] -gen-llvm = [] +gen-llvm = ["roc_build/llvm"] gen-dev = [] gen-wasm = [] wasm-cli-run = [] diff --git a/compiler/test_gen/src/gen_num.rs b/compiler/test_gen/src/gen_num.rs index 50f026bb4f..f81c2c9d43 100644 --- a/compiler/test_gen/src/gen_num.rs +++ b/compiler/test_gen/src/gen_num.rs @@ -357,6 +357,66 @@ fn u8_hex_int_alias() { ); } +#[test] +fn character_literal() { + assert_evals_to!( + indoc!( + r#" + x = 'A' + + x + "# + ), + 65, + u32 + ); +} + +#[test] +fn character_literal_back_slash() { + assert_evals_to!( + indoc!( + r#" + x = '\\' + + x + "# + ), + 92, + u32 + ); +} + +#[test] +fn character_literal_single_quote() { + assert_evals_to!( + indoc!( + r#" + x = '\'' + + x + "# + ), + 39, + u32 + ); +} + +#[test] +fn character_literal_new_line() { + assert_evals_to!( + indoc!( + r#" + x = '\n' + + x + "# + ), + 10, + u32 + ); +} + #[test] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn dec_float_alias() { diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index 3227c58796..c7868ee67f 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -1862,6 +1862,13 @@ impl UnionTags { slice.length == 1 } + pub fn is_newtype_wrapper_of_global_tag(&self, subs: &Subs) -> bool { + self.is_newtype_wrapper(subs) && { + let tags = &subs.tag_names[self.tag_names().indices()]; + matches!(tags[0], TagName::Global(_)) + } + } + pub fn from_tag_name_index(index: SubsIndex) -> Self { Self::from_slices( SubsSlice::new(index.index, 1), diff --git a/compiler/types/src/types.rs b/compiler/types/src/types.rs index bb10d3cdd4..186aac2a93 100644 --- a/compiler/types/src/types.rs +++ b/compiler/types/src/types.rs @@ -1304,6 +1304,7 @@ pub enum Category { Num, List, Str, + Character, // records Record, @@ -1325,6 +1326,7 @@ pub enum PatternCategory { Num, Int, Float, + Character, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] diff --git a/editor/src/editor/render_ast.rs b/editor/src/editor/render_ast.rs index 8dcda658e7..d66457a79e 100644 --- a/editor/src/editor/render_ast.rs +++ b/editor/src/editor/render_ast.rs @@ -3,9 +3,15 @@ use crate::editor::{ed_error::EdResult, theme::EdTheme, util::map_get}; use crate::graphics::primitives::rect::Rect; use crate::graphics::primitives::text as gr_text; use cgmath::Vector2; -use roc_code_markup::markup::nodes::{MarkupNode, BLANK_PLACEHOLDER}; -use roc_code_markup::slow_pool::{MarkNodeId, SlowPool}; -use roc_code_markup::syntax_highlight::HighlightStyle; +use roc_code_markup::{ + markup::{ + attribute::Attribute, + nodes::{MarkupNode, BLANK_PLACEHOLDER}, + }, + slow_pool::{MarkNodeId, SlowPool}, + syntax_highlight::HighlightStyle, + underline_style::UnderlineStyle, +}; use winit::dpi::PhysicalSize; use crate::{editor::config::Config, graphics::colors}; @@ -94,6 +100,9 @@ fn markup_to_wgpu_helper<'a>( txt_row_col: &mut (usize, usize), mark_node_pool: &'a SlowPool, ) -> EdResult<()> { + let char_width = code_style.glyph_dim_rect.width; + let char_height = code_style.glyph_dim_rect.height; + match markup_node { MarkupNode::Nested { ast_node_id: _, @@ -124,7 +133,7 @@ fn markup_to_wgpu_helper<'a>( content, ast_node_id: _, syn_high_style, - attributes: _, + attributes, parent_id_opt: _, newlines_at_end, } => { @@ -132,10 +141,38 @@ fn markup_to_wgpu_helper<'a>( let full_content = markup_node.get_full_content().replace("\n", "\\n"); // any \n left here should be escaped so that it can be shown as \n - let glyph_text = glyph_brush::OwnedText::new(full_content) + let glyph_text = glyph_brush::OwnedText::new(&full_content) .with_color(colors::to_slice(*highlight_color)) .with_scale(code_style.font_size); + for attribute in &attributes.all { + match attribute { + Attribute::Underline { underline_spec: _ } => { + // TODO use underline_spec + let top_left_coords = ( + code_style.txt_coords.x + (txt_row_col.1 as f32) * char_width, + code_style.txt_coords.y + + (txt_row_col.0 as f32) * char_height + + 1.0 * char_height, + ); + + let underline_rect = Rect { + top_left_coords: top_left_coords.into(), + width: char_width * (full_content.len() as f32), + height: 5.0, + color: *code_style + .ed_theme + .underline_color_map + .get(&UnderlineStyle::Error) + .unwrap(), + }; + + rects.push(underline_rect); + } + rest => todo!("handle Attribute: {:?}", rest), + } + } + txt_row_col.1 += content.len(); for _ in 0..*newlines_at_end { @@ -160,9 +197,6 @@ fn markup_to_wgpu_helper<'a>( let highlight_color = map_get(&code_style.ed_theme.syntax_high_map, &HighlightStyle::Blank)?; - let char_width = code_style.glyph_dim_rect.width; - let char_height = code_style.glyph_dim_rect.height; - let blank_rect = Rect { top_left_coords: ( code_style.txt_coords.x + (txt_row_col.1 as f32) * char_width, diff --git a/editor/src/editor/theme.rs b/editor/src/editor/theme.rs index 30e45a47a9..d3482f2cbe 100644 --- a/editor/src/editor/theme.rs +++ b/editor/src/editor/theme.rs @@ -1,5 +1,8 @@ use gr_colors::{from_hsb, RgbaTup}; -use roc_code_markup::syntax_highlight::{default_highlight_map, HighlightStyle}; +use roc_code_markup::{ + syntax_highlight::{default_highlight_map, HighlightStyle}, + underline_style::{default_underline_color_map, UnderlineStyle}, +}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -12,6 +15,7 @@ pub struct EdTheme { pub subtle_text: RgbaTup, pub syntax_high_map: HashMap, pub ui_theme: UITheme, + pub underline_color_map: HashMap, } impl Default for EdTheme { @@ -21,6 +25,7 @@ impl Default for EdTheme { subtle_text: from_hsb(240, 5, 60), syntax_high_map: default_highlight_map(), ui_theme: UITheme::default(), + underline_color_map: default_underline_color_map(), } } } diff --git a/editor/src/graphics/primitives/rect.rs b/editor/src/graphics/primitives/rect.rs index 7560c0d10a..ddf26f1199 100644 --- a/editor/src/graphics/primitives/rect.rs +++ b/editor/src/graphics/primitives/rect.rs @@ -1,9 +1,19 @@ use cgmath::Vector2; +/// These fields are ordered this way because in Roc, the corresponding stuct is: +/// +/// { top : F32, left : F32, width : F32, height : F32 } +/// +/// alphabetically, that's { height, left, top, width } - which works out to the same as: +/// +/// height: f32, pos: Vector2, width: f32 +/// +/// ...because Vector2 is a repr(C) struct of { x: f32, y: f32 } #[derive(Debug, Copy, Clone)] +#[repr(C)] pub struct Rect { + pub color: (f32, f32, f32, f32), + pub height: f32, pub top_left_coords: Vector2, pub width: f32, - pub height: f32, - pub color: (f32, f32, f32, f32), } diff --git a/examples/gui/.gitignore b/examples/gui/.gitignore new file mode 100644 index 0000000000..8f5562e399 --- /dev/null +++ b/examples/gui/.gitignore @@ -0,0 +1 @@ +hello-gui diff --git a/examples/gui/Hello.roc b/examples/gui/Hello.roc new file mode 100644 index 0000000000..c15f5bd21a --- /dev/null +++ b/examples/gui/Hello.roc @@ -0,0 +1,23 @@ +app "hello-gui" + packages { pf: "platform" } + imports []# [ pf.Action.{ Action }, pf.Elem.{ button, text, row, col } ] + provides [ render ] to pf + +render = + div0 = \numerator, denominator -> (numerator / denominator) |> Result.withDefault 0 + + rgba = \r, g, b, a -> { r: div0 r 255, g: div0 g 255, b: div0 b 255, a } + + styles = { bgColor: rgba 100 50 50 1, borderColor: rgba 10 20 30 1, borderWidth: 10, textColor: rgba 220 220 250 1 } + + Col + [ + Row + [ + Button (Text "Corner ") styles, + Button (Text "Top Mid ") { styles & bgColor: rgba 100 100 50 1 }, + Button (Text "Top Right ") { styles & bgColor: rgba 50 50 150 1 }, + ], + Button (Text "Mid Left ") { styles & bgColor: rgba 150 100 100 1 }, + Button (Text "Bottom Left") { styles & bgColor: rgba 150 50 50 1 }, + ] diff --git a/examples/gui/platform/Action.roc b/examples/gui/platform/Action.roc new file mode 100644 index 0000000000..ad15ee728b --- /dev/null +++ b/examples/gui/platform/Action.roc @@ -0,0 +1,20 @@ +interface Action + exposes [ Action, none, update, map ] + imports [] + +Action state : [ None, Update state ] + +none : Action * +none = None + +update : state -> Action state +update = Update + +map : Action a, (a -> b) -> Action b +map = \action, transform -> + when action is + None -> + None + + Update state -> + Update (transform state) diff --git a/examples/gui/platform/Cargo.lock b/examples/gui/platform/Cargo.lock new file mode 100644 index 0000000000..9ce6ea7d8d --- /dev/null +++ b/examples/gui/platform/Cargo.lock @@ -0,0 +1,2826 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61caed9aec6daeee1ea38ccf5fb225e4f96c1eeead1b4a5c267324a63cf02326" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13739d7177fbd22bb0ed28badfff9f372f8bef46c863db4e1c6248f6b223b6e" + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "alsa" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18" +dependencies = [ + "alsa-sys", + "bitflags", + "libc", + "nix 0.20.0", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "approx" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" +dependencies = [ + "num-traits", +] + +[[package]] +name = "approx" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "072df7202e63b127ab55acfe16ce97013d5b97bf160489336d3f1840fd78e99e" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "ash" +version = "0.35.1+1.2.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7fd04def1c9101b5fb488c131022d2d6f87753ef4b1b11b279e2af404fae6b9" +dependencies = [ + "libloading", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "backtrace" +version = "0.3.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bindgen" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", +] + +[[package]] +name = "bit-set" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "bytemuck" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e215f8c2f9f79cb53c8335e687ffd07d5bfcb6fe5fc80723762d0be46e7cc54" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "calloop" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf2eec61efe56aa1e813f5126959296933cf0700030e4314786c48779a66ab82" +dependencies = [ + "log", + "nix 0.22.0", +] + +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +dependencies = [ + "nom 5.1.2", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cgmath" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" +dependencies = [ + "approx 0.4.0", + "num-traits", +] + +[[package]] +name = "clang-sys" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "claxon" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688" + +[[package]] +name = "clipboard-win" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342" +dependencies = [ + "lazy-bytes-cast", + "winapi", +] + +[[package]] +name = "cocoa" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation 0.9.2", + "core-graphics 0.22.3", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation 0.9.2", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "combine" +version = "4.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "confy" +version = "0.4.0" +source = "git+https://github.com/rust-cli/confy#664992aecd97b4af0eda8d9d2825885662e1c6b4" +dependencies = [ + "directories-next", + "serde", + "serde_yaml", +] + +[[package]] +name = "copyless" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" + +[[package]] +name = "copypasta" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4423d79fed83ebd9ab81ec21fa97144300a961782158287dc9bf7eddac37ff0b" +dependencies = [ + "clipboard-win", + "objc", + "objc-foundation", + "objc_id", + "smithay-clipboard", + "x11-clipboard", +] + +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys 0.7.0", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +dependencies = [ + "core-foundation-sys 0.8.3", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core-graphics" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" +dependencies = [ + "bitflags", + "core-foundation 0.7.0", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation 0.9.2", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation 0.9.2", + "foreign-types", + "libc", +] + +[[package]] +name = "core-video-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" +dependencies = [ + "cfg-if 0.1.10", + "core-foundation-sys 0.7.0", + "core-graphics 0.19.2", + "libc", + "objc", +] + +[[package]] +name = "coreaudio-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" +dependencies = [ + "bitflags", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98f45f0a21f617cd2c788889ef710b63f075c949259593ea09c826f1e47a2418" +dependencies = [ + "alsa", + "core-foundation-sys 0.8.3", + "coreaudio-rs", + "jni", + "js-sys", + "lazy_static", + "libc", + "mach", + "ndk 0.3.0", + "ndk-glue 0.3.0", + "nix 0.20.0", + "oboe", + "parking_lot", + "stdweb", + "thiserror", + "web-sys", + "winapi", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" +dependencies = [ + "cfg-if 1.0.0", + "lazy_static", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "d3d12" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2daefd788d1e96e0a9d66dee4b828b883509bc3ea9ce30665f04c3246372690c" +dependencies = [ + "bitflags", + "libloading", + "winapi", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core 0.10.2", + "darling_macro 0.10.2", +] + +[[package]] +name = "darling" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" +dependencies = [ + "darling_core 0.13.1", + "darling_macro 0.13.1", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.9.3", + "syn", +] + +[[package]] +name = "darling_core" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core 0.10.2", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" +dependencies = [ + "darling_core 0.13.1", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +dependencies = [ + "libloading", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "env_logger" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "find-crate" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2" +dependencies = [ + "toml", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "fs_extra" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" + +[[package]] +name = "futures" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" + +[[package]] +name = "futures-executor" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" + +[[package]] +name = "futures-macro" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" + +[[package]] +name = "futures-task" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" + +[[package]] +name = "futures-util" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "getrandom" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "glow" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glyph_brush" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21932fbf719272848eec4583740d978203c6e7da4c4e203358f5b95946c97409" +dependencies = [ + "glyph_brush_draw_cache", + "glyph_brush_layout", + "log", + "ordered-float", + "rustc-hash", + "twox-hash", +] + +[[package]] +name = "glyph_brush_draw_cache" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6010675390f6889e09a21e2c8b575b3ee25667ea8237a8d59423f73cb8c28610" +dependencies = [ + "ab_glyph", + "crossbeam-channel", + "crossbeam-deque", + "linked-hash-map", + "rayon", + "rustc-hash", +] + +[[package]] +name = "glyph_brush_layout" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc32c2334f00ca5ac3695c5009ae35da21da8c62d255b5b96d56e2597a637a38" +dependencies = [ + "ab_glyph", + "approx 0.5.0", + "xi-unicode", +] + +[[package]] +name = "gpu-alloc" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d" +dependencies = [ + "bitflags", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" +dependencies = [ + "bitflags", +] + +[[package]] +name = "gpu-descriptor" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a538f217be4d405ff4719a283ca68323cc2384003eca5baaa87501e821c81dda" +dependencies = [ + "bitflags", + "gpu-descriptor-types", + "hashbrown", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126" +dependencies = [ + "bitflags", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "host" +version = "0.1.0" +dependencies = [ + "arrayvec", + "bytemuck", + "cgmath", + "colored", + "confy", + "copypasta", + "env_logger", + "fs_extra", + "futures", + "glyph_brush", + "libc", + "log", + "nonempty", + "page_size", + "palette", + "pest", + "pest_derive", + "roc_std", + "rodio", + "serde", + "snafu", + "threadpool", + "wgpu", + "wgpu_glyph", + "winit", +] + +[[package]] +name = "hound" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "inplace_it" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +dependencies = [ + "libc", + "libloading", + "pkg-config", +] + +[[package]] +name = "lazy-bytes-cast" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lewton" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" +dependencies = [ + "byteorder", + "ogg", + "tinyvec", +] + +[[package]] +name = "libc" +version = "0.2.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9" + +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memmap2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metal" +version = "0.23.1" +source = "git+https://github.com/gfx-rs/metal-rs?rev=44af5cc#44af5cca340617d42d701264f9bf71d1f3e68096" +dependencies = [ + "bitflags", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "minimp3" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985438f75febf74c392071a975a29641b420dd84431135a6e6db721de4b74372" +dependencies = [ + "minimp3-sys", + "slice-deque", + "thiserror", +] + +[[package]] +name = "minimp3-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e21c73734c69dc95696c9ed8926a2b393171d98b3f5f5935686a26a487ab9b90" +dependencies = [ + "cc", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "mio" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "naga" +version = "0.8.0" +source = "git+https://github.com/gfx-rs/naga?rev=8e2e39e#8e2e39e4d8fa5bbb657c3b170b4f6607d703e284" +dependencies = [ + "bit-set", + "bitflags", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "num-traits", + "rustc-hash", + "spirv", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" +dependencies = [ + "jni-sys", + "ndk-sys 0.2.2", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d868f654c72e75f8687572699cdabe755f03effbb62542768e995d5b8d699d" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.2.2", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.3.0", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-glue" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.3.0", + "ndk-macro 0.2.0", + "ndk-sys 0.2.2", +] + +[[package]] +name = "ndk-glue" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc291b8de2095cba8dab7cf381bf582ff4c17a09acf854c32e46545b08085d28" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.5.0", + "ndk-macro 0.3.0", + "ndk-sys 0.2.2", +] + +[[package]] +name = "ndk-glue" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c0d14b0858eb9962a5dac30b809b19f19da7e4547d64af2b0bb051d2e55d79" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.6.0", + "ndk-macro 0.3.0", + "ndk-sys 0.3.0", +] + +[[package]] +name = "ndk-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" +dependencies = [ + "darling 0.10.2", + "proc-macro-crate 0.1.5", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" +dependencies = [ + "darling 0.13.1", + "proc-macro-crate 1.1.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", +] + +[[package]] +name = "nix" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1e25ee6b412c2a1e3fcb6a4499a5c1bfe7f43e014bdce9a6b6666e5aa2d187" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", +] + +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "nom" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +dependencies = [ + "memchr", + "minimal-lexical", + "version_check", +] + +[[package]] +name = "nonempty" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" +dependencies = [ + "proc-macro-crate 1.1.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "object" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +dependencies = [ + "memchr", +] + +[[package]] +name = "oboe" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2463c8f2e19b4e0d0710a21f8e4011501ff28db1c95d7a5482a553b2100502d2" +dependencies = [ + "jni", + "ndk 0.6.0", + "ndk-glue 0.6.0", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd" +dependencies = [ + "cc", +] + +[[package]] +name = "ogg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" +dependencies = [ + "byteorder", +] + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "ordered-float" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +dependencies = [ + "num-traits", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef05f2882a8b3e7acc10c153ade2631f7bfc8ce00d2bf3fb8f4e9d2ae6ea5c3" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "page_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "palette" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9735f7e1e51a3f740bacd5dc2724b61a7806f23597a8736e679f38ee3435d18" +dependencies = [ + "approx 0.5.0", + "num-traits", + "palette_derive", + "phf", +] + +[[package]] +name = "palette_derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7799c3053ea8a6d8a1193c7ba42f534e7863cf52e378a7f90406f4a645d33bad" +dependencies = [ + "find-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1", +] + +[[package]] +name = "phf" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37" +dependencies = [ + "phf_macros", + "phf_shared", + "proc-macro-hack", +] + +[[package]] +name = "phf_generator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" +dependencies = [ + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "profiling" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9145ac0af1d93c638c98c40cf7d25665f427b2a44ad0a99b1dccf3e2f25bb987" + +[[package]] +name = "quick-xml" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "range-alloc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6" + +[[package]] +name = "raw-window-handle" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba75eee94a9d5273a68c9e1e105d9cffe1ef700532325788389e5a83e2522b7" +dependencies = [ + "cty", +] + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "renderdoc-sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" + +[[package]] +name = "roc_std" +version = "0.1.0" + +[[package]] +name = "rodio" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d98f5e557b61525057e2bc142c8cd7f0e70d75dc32852309bec440e6e046bf9" +dependencies = [ + "claxon", + "cpal", + "hound", + "lewton", + "minimp3", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.135" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cf9235533494ea2ddcdb794665461814781c53f19d87b76e571a1c35acbad2b" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.135" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dcde03d87d4c973c04be249e7d8f0b35db1c848c487bd43032808e59dd8328d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yaml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" +dependencies = [ + "indexmap", + "ryu", + "serde", + "yaml-rust", +] + +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", +] + +[[package]] +name = "shlex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" + +[[package]] +name = "siphasher" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e" + +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + +[[package]] +name = "slice-deque" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31ef6ee280cdefba6d2d0b4b78a84a1c1a3f3a4cec98c2d4231c8bc225de0f25" +dependencies = [ + "libc", + "mach", + "winapi", +] + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "smithay-client-toolkit" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1325f292209cee78d5035530932422a30aa4c8fda1a16593ac083c1de211e68a" +dependencies = [ + "bitflags", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2", + "nix 0.22.0", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "smithay-clipboard" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610b551bd25378bfd2b8e7a0fcbd83d427e8f2f6a40c47ae0f70688e9949dd55" +dependencies = [ + "smithay-client-toolkit", + "wayland-client", +] + +[[package]] +name = "snafu" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7" +dependencies = [ + "backtrace", + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "spirv" +version = "0.2.0+1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +dependencies = [ + "bitflags", + "num-traits", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stdweb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "ttf-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ccbe8381883510b6a2d8f1e32905bddd178c11caef8083086d0c0c9ab0ac281" + +[[package]] +name = "twox-hash" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" +dependencies = [ + "cfg-if 1.0.0", + "rand", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasm-bindgen" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" + +[[package]] +name = "wayland-client" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f" +dependencies = [ + "bitflags", + "downcast-rs", + "libc", + "nix 0.22.0", + "scoped-tls", + "wayland-commons", + "wayland-scanner", + "wayland-sys", +] + +[[package]] +name = "wayland-commons" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e" +dependencies = [ + "nix 0.22.0", + "once_cell", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-cursor" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd" +dependencies = [ + "nix 0.22.0", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741" +dependencies = [ + "bitflags", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4" +dependencies = [ + "dlib", + "lazy_static", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wgpu" +version = "0.12.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=0545e36#0545e36aa82709cca78c14eb3813f10eea7a9275" +dependencies = [ + "arrayvec", + "js-sys", + "log", + "naga", + "parking_lot", + "raw-window-handle", + "smallvec", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.12.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=0545e36#0545e36aa82709cca78c14eb3813f10eea7a9275" +dependencies = [ + "arrayvec", + "bitflags", + "cfg_aliases", + "codespan-reporting", + "copyless", + "fxhash", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "thiserror", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.12.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=0545e36#0545e36aa82709cca78c14eb3813f10eea7a9275" +dependencies = [ + "arrayvec", + "ash", + "bit-set", + "bitflags", + "block", + "core-graphics-types", + "d3d12", + "foreign-types", + "fxhash", + "glow", + "gpu-alloc", + "gpu-descriptor", + "inplace_it", + "js-sys", + "khronos-egl", + "libloading", + "log", + "metal", + "naga", + "objc", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.12.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=0545e36#0545e36aa82709cca78c14eb3813f10eea7a9275" +dependencies = [ + "bitflags", +] + +[[package]] +name = "wgpu_glyph" +version = "0.16.0" +source = "git+https://github.com/Anton-4/wgpu_glyph?rev=257d109#257d1098cbafa3c8a0a2465937b06fc730fc6ffb" +dependencies = [ + "bytemuck", + "glyph_brush", + "log", + "wgpu", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winit" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b43cc931d58b99461188607efd7acb2a093e65fc621f54cad78517a6063e73a" +dependencies = [ + "bitflags", + "cocoa", + "core-foundation 0.9.2", + "core-graphics 0.22.3", + "core-video-sys", + "dispatch", + "instant", + "lazy_static", + "libc", + "log", + "mio", + "ndk 0.5.0", + "ndk-glue 0.5.0", + "ndk-sys 0.2.2", + "objc", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "smithay-client-toolkit", + "wasm-bindgen", + "wayland-client", + "wayland-protocols", + "web-sys", + "winapi", + "x11-dl", +] + +[[package]] +name = "x11-clipboard" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473068b7b80ac86a18328824f1054e5e007898c47b5bbc281bd7abe32bc3653c" +dependencies = [ + "xcb", +] + +[[package]] +name = "x11-dl" +version = "2.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +dependencies = [ + "lazy_static", + "libc", + "pkg-config", +] + +[[package]] +name = "xcb" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771e2b996df720cd1c6dd9ff90f62d91698fd3610cc078388d0564bdd6622a9c" +dependencies = [ + "libc", + "log", + "quick-xml", +] + +[[package]] +name = "xcursor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +dependencies = [ + "nom 7.1.0", +] + +[[package]] +name = "xi-unicode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/examples/gui/platform/Cargo.toml b/examples/gui/platform/Cargo.toml new file mode 100644 index 0000000000..b82712e562 --- /dev/null +++ b/examples/gui/platform/Cargo.toml @@ -0,0 +1,76 @@ +[package] +name = "host" +version = "0.1.0" +authors = ["The Roc Contributors"] +license = "UPL-1.0" +edition = "2018" +links = "app" + +# Needed to be able to run on non-Windows systems for some reason. Without this, cargo panics with: +# +# error: DX12 API enabled on non-Windows OS. If your project is not using resolver="2" in Cargo.toml, it should. +resolver = "2" + +[lib] +name = "host" +path = "src/lib.rs" +crate-type = ["staticlib", "rlib"] + +[[bin]] +name = "host" +path = "src/main.rs" + +[dependencies] +roc_std = { path = "../../../roc_std" } +libc = "0.2" +arrayvec = "0.7.2" +page_size = "0.4.2" +# when changing winit version, check if copypasta can be updated simultaneously so they use the same versions for their dependencies. This will save build time. +winit = "0.26.1" +wgpu = { git = "https://github.com/gfx-rs/wgpu", rev = "0545e36" } +wgpu_glyph = { git = "https://github.com/Anton-4/wgpu_glyph", rev = "257d109" } +glyph_brush = "0.7.2" +log = "0.4.14" +env_logger = "0.9.0" +futures = "0.3.17" +cgmath = "0.18.0" +snafu = { version = "0.6.10", features = ["backtraces"] } +colored = "2.0.0" +pest = "2.1.3" +pest_derive = "2.1.0" +copypasta = "0.7.1" +palette = "0.6.0" +confy = { git = 'https://github.com/rust-cli/confy', features = [ + "yaml_conf" +], default-features = false } +serde = { version = "1.0.130", features = ["derive"] } +nonempty = "0.7.0" +fs_extra = "1.2.0" +rodio = { version = "0.14.0", optional = true } # to play sounds +threadpool = "1.8.1" + +[package.metadata.cargo-udeps.ignore] +# confy is currently unused but should not be removed +normal = ["confy"] +#development = [] +#build = [] + +[features] +default = [] +with_sound = ["rodio"] + +[dependencies.bytemuck] +version = "1.7.2" +features = ["derive"] + +[workspace] + +# Optimizations based on https://deterministic.space/high-performance-rust.html +[profile.release] +lto = "thin" +codegen-units = 1 + +# debug = true # enable when profiling +[profile.bench] +lto = "thin" +codegen-units = 1 diff --git a/examples/gui/platform/Elem.roc b/examples/gui/platform/Elem.roc new file mode 100644 index 0000000000..519d007b99 --- /dev/null +++ b/examples/gui/platform/Elem.roc @@ -0,0 +1,193 @@ +interface Elem + exposes [ Elem, PressEvent, row, col, text, button, none, translate, list ] + imports [ Action.{ Action } ] + +Elem state : + # PERFORMANCE NOTE: + # If there are 8 or fewer tags here, then on a 64-bit system, the tag can be stored + # in the pointer - for massive memory savings. Try extremely hard to always limit the number + # of tags in this union to 8 or fewer! + [ + Button (ButtonConfig state) (Elem state), + Text Str, + Col (List (Elem state)), + Row (List (Elem state)), + Lazy (Result { state, elem : Elem state } [ NotCached ] -> { state, elem : Elem state }), + # TODO FIXME: using this definition of Lazy causes a stack overflow in the compiler! + # Lazy (Result (Cached state) [ NotCached ] -> Cached state), + None, + ] + +## Used internally in the type definition of Lazy +Cached state : { state, elem : Elem state } + +ButtonConfig state : { onPress : state, PressEvent -> Action state } + +PressEvent : { button : [ Touch, Mouse [ Left, Right, Middle ] ] } + +text : Str -> Elem * +text = \str -> + Text str + +button : { onPress : state, PressEvent -> Action state }, Elem state -> Elem state +button = \config, label -> + Button config label + +row : List (Elem state) -> Elem state +row = \children -> + Row children + +col : List (Elem state) -> Elem state +col = \children -> + Col children + +lazy : state, (state -> Elem state) -> Elem state +lazy = \state, render -> + # This function gets called by the host during rendering. It will + # receive the cached state and element (wrapped in Ok) if we've + # ever rendered this before, and Err otherwise. + Lazy + \result -> + when result is + Ok cached if cached.state == state -> + # If we have a cached value, and the new state is the + # same as the cached one, then we can return exactly + # what we had cached. + cached + + _ -> + # Either the state changed or else we didn't have a + # cached value to use. Either way, we need to render + # with the new state and store that for future use. + { state, elem: render state } + +none : Elem * +none = None# I've often wanted this in elm/html. Usually end up resorting to (Html.text "") - this seems nicer. +## Change an element's state type. +## +## TODO: indent the following once https://github.com/rtfeldman/roc/issues/2585 is fixed. +## State : { photo : Photo } +## +## render : State -> Elem State +## render = \state -> +## child : Elem State +## child = +## Photo.render state.photo +## |> Elem.translate .photo &photo +## +## col {} [ child, otherElems ] +## +translate = \child, toChild, toParent -> + when child is + Text str -> + Text str + + Col elems -> + Col (List.map elems \elem -> translate elem toChild toParent) + + Row elems -> + Row (List.map elems \elem -> translate elem toChild toParent) + + Button config label -> + onPress = \parentState, event -> + toChild parentState + |> config.onPress event + |> Action.map \c -> toParent parentState c + + Button { onPress } (translate label toChild toParent) + + Lazy renderChild -> + Lazy + \parentState -> + { elem, state } = renderChild (toChild parentState) + + { + elem: translate toChild toParent newChild, + state: toParent parentState state, + } + + None -> + None + +## Render a list of elements, using [Elem.translate] on each of them. +## +## Convenient when you have a [List] in your state and want to make +## a [List] of child elements out of it. +## +## TODO: indent the following once https://github.com/rtfeldman/roc/issues/2585 is fixed. +## State : { photos : List Photo } +## +## render : State -> Elem State +## render = \state -> +## children : List (Elem State) +## children = +## Elem.list Photo.render state .photos &photos +## +## col {} children +## TODO: format as multiline type annotation once https://github.com/rtfeldman/roc/issues/2586 is fixed +list : (child -> Elem child), parent, (parent -> List child), (parent, List child -> parent) -> List (Elem parent) +list = \renderChild, parent, toChildren, toParent -> + List.mapWithIndex + (toChildren parent) + \index, child -> + toChild = \par -> List.get (toChildren par) index + + newChild = translateOrDrop + child + toChild + \par, ch -> + toChildren par + |> List.set ch index + |> toParent + + renderChild newChild + +## Internal helper function for Elem.list +## +## Tries to translate a child to a parent, but +## if the child has been removed from the parent, +## drops it. +## +## TODO: format as multiline type annotation once https://github.com/rtfeldman/roc/issues/2586 is fixed +translateOrDrop : Elem child, (parent -> Result child *), (parent, child -> parent) -> Elem parent +translateOrDrop = \child, toChild, toParent -> + when child is + Text str -> + Text str + + Col elems -> + Col (List.map elems \elem -> translateOrDrop elem toChild toParent) + + Row elems -> + Row (List.map elems \elem -> translateOrDrop elem toChild toParent) + + Button config label -> + onPress = \parentState, event -> + when toChild parentState is + Ok newChild -> + newChild + |> config.onPress event + |> Action.map \c -> toParent parentState c + + Err _ -> + # The child was removed from the list before this onPress handler resolved. + # (For example, by a previous event handler that fired simultaneously.) + Action.none + + Button { onPress } (translateOrDrop label toChild toParent) + + Lazy childState renderChild -> + Lazy + (toParent childState) + \parentState -> + when toChild parentState is + Ok newChild -> + renderChild newChild + |> translateOrDrop toChild toParent + + Err _ -> + None + + # I don't think this should ever happen in practice. + None -> + None diff --git a/examples/gui/platform/Package-Config.roc b/examples/gui/platform/Package-Config.roc new file mode 100644 index 0000000000..855c45e23b --- /dev/null +++ b/examples/gui/platform/Package-Config.roc @@ -0,0 +1,15 @@ +platform "examples/hello-world" + requires {} { render : Elem } + exposes [] + packages {} + imports [] + provides [ renderForHost ] + +Rgba : { r : F32, g : F32, b : F32, a : F32 } + +ButtonStyles : { bgColor : Rgba, borderColor : Rgba, borderWidth : F32, textColor : Rgba } + +Elem : [ Button Elem ButtonStyles, Col (List Elem), Row (List Elem), Text Str ] + +renderForHost : Elem +renderForHost = render diff --git a/examples/gui/platform/build.rs b/examples/gui/platform/build.rs new file mode 100644 index 0000000000..73159e387c --- /dev/null +++ b/examples/gui/platform/build.rs @@ -0,0 +1,4 @@ +fn main() { + println!("cargo:rustc-link-lib=dylib=app"); + println!("cargo:rustc-link-search=."); +} diff --git a/examples/gui/platform/host.c b/examples/gui/platform/host.c new file mode 100644 index 0000000000..b9214bcf33 --- /dev/null +++ b/examples/gui/platform/host.c @@ -0,0 +1,3 @@ +extern int rust_main(); + +int main() { return rust_main(); } \ No newline at end of file diff --git a/examples/gui/platform/src/graphics/colors.rs b/examples/gui/platform/src/graphics/colors.rs new file mode 100644 index 0000000000..e0932a1d69 --- /dev/null +++ b/examples/gui/platform/src/graphics/colors.rs @@ -0,0 +1,50 @@ +use cgmath::Vector4; +use palette::{FromColor, Hsv, Srgb}; + +/// This order is optimized for what Roc will send +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Rgba { + a: f32, + b: f32, + g: f32, + r: f32, +} + +impl Rgba { + pub const WHITE: Self = Self::new(1.0, 1.0, 1.0, 1.0); + + pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self { + Self { r, g, b, a } + } + + pub const fn to_array(self) -> [f32; 4] { + [self.r, self.b, self.g, self.a] + } + + pub fn from_hsb(hue: usize, saturation: usize, brightness: usize) -> Self { + Self::from_hsba(hue, saturation, brightness, 1.0) + } + + pub fn from_hsba(hue: usize, saturation: usize, brightness: usize, alpha: f32) -> Self { + let rgb = Srgb::from_color(Hsv::new( + hue as f32, + (saturation as f32) / 100.0, + (brightness as f32) / 100.0, + )); + + Self::new(rgb.red, rgb.green, rgb.blue, alpha) + } +} + +impl From for [f32; 4] { + fn from(rgba: Rgba) -> Self { + rgba.to_array() + } +} + +impl From for Vector4 { + fn from(rgba: Rgba) -> Self { + Vector4::new(rgba.r, rgba.b, rgba.g, rgba.a) + } +} diff --git a/examples/gui/platform/src/graphics/lowlevel/buffer.rs b/examples/gui/platform/src/graphics/lowlevel/buffer.rs new file mode 100644 index 0000000000..dbe0270e57 --- /dev/null +++ b/examples/gui/platform/src/graphics/lowlevel/buffer.rs @@ -0,0 +1,96 @@ +// Contains parts of https://github.com/sotrh/learn-wgpu +// by Benjamin Hansen - license information can be found in the LEGAL_DETAILS +// file in the root directory of this distribution. +// +// Thank you, Benjamin! + +// Contains parts of https://github.com/iced-rs/iced/blob/adce9e04213803bd775538efddf6e7908d1c605e/wgpu/src/shader/quad.wgsl +// By Héctor Ramón, Iced contributors Licensed under the MIT license. +// The license is included in the LEGAL_DETAILS file in the root directory of this distribution. + +// Thank you Héctor Ramón and Iced contributors! + +use std::mem; + +use super::{quad::Quad, vertex::Vertex}; +use crate::graphics::primitives::rect::RectElt; +use wgpu::util::DeviceExt; + +pub struct RectBuffers { + pub vertex_buffer: wgpu::Buffer, + pub index_buffer: wgpu::Buffer, + pub quad_buffer: wgpu::Buffer, +} + +pub const QUAD_INDICES: [u16; 6] = [0, 1, 2, 0, 2, 3]; + +const QUAD_VERTS: [Vertex; 4] = [ + Vertex { + _position: [0.0, 0.0], + }, + Vertex { + _position: [1.0, 0.0], + }, + Vertex { + _position: [1.0, 1.0], + }, + Vertex { + _position: [0.0, 1.0], + }, +]; + +pub const MAX_QUADS: usize = 100_000; + +pub fn create_rect_buffers( + gpu_device: &wgpu::Device, + cmd_encoder: &mut wgpu::CommandEncoder, + rects: &[RectElt], +) -> RectBuffers { + let vertex_buffer = gpu_device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: None, + contents: bytemuck::cast_slice(&QUAD_VERTS), + usage: wgpu::BufferUsages::VERTEX, + }); + + let index_buffer = gpu_device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: None, + contents: bytemuck::cast_slice(&QUAD_INDICES), + usage: wgpu::BufferUsages::INDEX, + }); + + let quad_buffer = gpu_device.create_buffer(&wgpu::BufferDescriptor { + label: Some("iced_wgpu::quad instance buffer"), + size: mem::size_of::() as u64 * MAX_QUADS as u64, + usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + let quads: Vec = rects.iter().map(|rect| to_quad(rect)).collect(); + + let buffer_size = (quads.len() as u64) * Quad::SIZE; + + let staging_buffer = gpu_device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: None, + contents: bytemuck::cast_slice(&quads), + usage: wgpu::BufferUsages::COPY_SRC, + }); + + cmd_encoder.copy_buffer_to_buffer(&staging_buffer, 0, &quad_buffer, 0, buffer_size); + + RectBuffers { + vertex_buffer, + index_buffer, + quad_buffer, + } +} + +pub fn to_quad(rect_elt: &RectElt) -> Quad { + Quad { + pos: rect_elt.rect.pos.into(), + width: rect_elt.rect.width, + height: rect_elt.rect.height, + color: (rect_elt.color.to_array()), + border_color: rect_elt.border_color.into(), + border_width: rect_elt.border_width, + } +} diff --git a/examples/gui/platform/src/graphics/lowlevel/mod.rs b/examples/gui/platform/src/graphics/lowlevel/mod.rs new file mode 100644 index 0000000000..0add45385d --- /dev/null +++ b/examples/gui/platform/src/graphics/lowlevel/mod.rs @@ -0,0 +1,5 @@ +pub mod buffer; +pub mod ortho; +pub mod pipelines; +pub mod vertex; +pub mod quad; diff --git a/examples/gui/platform/src/graphics/lowlevel/ortho.rs b/examples/gui/platform/src/graphics/lowlevel/ortho.rs new file mode 100644 index 0000000000..2f4577871a --- /dev/null +++ b/examples/gui/platform/src/graphics/lowlevel/ortho.rs @@ -0,0 +1,118 @@ +use cgmath::{Matrix4, Ortho}; +use wgpu::util::DeviceExt; +use wgpu::{ + BindGroup, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, Buffer, + ShaderStages, +}; + +// orthographic projection is used to transform pixel coords to the coordinate system used by wgpu + +#[repr(C)] +#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +struct Uniforms { + // We can't use cgmath with bytemuck directly so we'll have + // to convert the Matrix4 into a 4x4 f32 array + ortho: [[f32; 4]; 4], +} + +impl Uniforms { + fn new(w: u32, h: u32) -> Self { + let ortho: Matrix4 = Ortho:: { + left: 0.0, + right: w as f32, + bottom: h as f32, + top: 0.0, + near: -1.0, + far: 1.0, + } + .into(); + Self { + ortho: ortho.into(), + } + } +} + +// update orthographic buffer according to new window size +pub fn update_ortho_buffer( + inner_width: u32, + inner_height: u32, + gpu_device: &wgpu::Device, + ortho_buffer: &Buffer, + cmd_queue: &wgpu::Queue, +) { + let new_uniforms = Uniforms::new(inner_width, inner_height); + + let new_ortho_buffer = gpu_device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Ortho uniform buffer"), + contents: bytemuck::cast_slice(&[new_uniforms]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_SRC, + }); + + // get a command encoder for the current frame + let mut encoder = gpu_device.create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Resize"), + }); + + // overwrite the new buffer over the old one + encoder.copy_buffer_to_buffer( + &new_ortho_buffer, + 0, + ortho_buffer, + 0, + (std::mem::size_of::() * vec![new_uniforms].as_slice().len()) + as wgpu::BufferAddress, + ); + + cmd_queue.submit(Some(encoder.finish())); +} + +#[derive(Debug)] +pub struct OrthoResources { + pub buffer: Buffer, + pub bind_group_layout: BindGroupLayout, + pub bind_group: BindGroup, +} + +pub fn init_ortho( + inner_width: u32, + inner_height: u32, + gpu_device: &wgpu::Device, +) -> OrthoResources { + let uniforms = Uniforms::new(inner_width, inner_height); + + let ortho_buffer = gpu_device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Ortho uniform buffer"), + contents: bytemuck::cast_slice(&[uniforms]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + + // bind groups consist of extra resources that are provided to the shaders + let ortho_bind_group_layout = gpu_device.create_bind_group_layout(&BindGroupLayoutDescriptor { + entries: &[BindGroupLayoutEntry { + binding: 0, + visibility: ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + label: Some("Ortho bind group layout"), + }); + + let ortho_bind_group = gpu_device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &ortho_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: ortho_buffer.as_entire_binding(), + }], + label: Some("Ortho bind group"), + }); + + OrthoResources { + buffer: ortho_buffer, + bind_group_layout: ortho_bind_group_layout, + bind_group: ortho_bind_group, + } +} diff --git a/examples/gui/platform/src/graphics/lowlevel/pipelines.rs b/examples/gui/platform/src/graphics/lowlevel/pipelines.rs new file mode 100644 index 0000000000..a0dc7908ec --- /dev/null +++ b/examples/gui/platform/src/graphics/lowlevel/pipelines.rs @@ -0,0 +1,72 @@ +use super::ortho::{init_ortho, OrthoResources}; +use super::quad::Quad; +use super::vertex::Vertex; +use std::borrow::Cow; + +pub struct RectResources { + pub pipeline: wgpu::RenderPipeline, + pub ortho: OrthoResources, +} + +pub fn make_rect_pipeline( + gpu_device: &wgpu::Device, + surface_config: &wgpu::SurfaceConfiguration, +) -> RectResources { + let ortho = init_ortho(surface_config.width, surface_config.height, gpu_device); + + let pipeline_layout = gpu_device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&ortho.bind_group_layout], + push_constant_ranges: &[], + }); + let pipeline = create_render_pipeline( + gpu_device, + &pipeline_layout, + surface_config.format, + &wgpu::ShaderModuleDescriptor { + label: None, + source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("../shaders/quad.wgsl"))), + }, + ); + + RectResources { pipeline, ortho } +} + +pub fn create_render_pipeline( + device: &wgpu::Device, + layout: &wgpu::PipelineLayout, + color_format: wgpu::TextureFormat, + shader_module_desc: &wgpu::ShaderModuleDescriptor, +) -> wgpu::RenderPipeline { + let shader = device.create_shader_module(shader_module_desc); + + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Render pipeline"), + layout: Some(layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + buffers: &[Vertex::DESC, Quad::DESC], + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + targets: &[wgpu::ColorTargetState { + format: color_format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent { + operation: wgpu::BlendOperation::Add, + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + }, + alpha: wgpu::BlendComponent::REPLACE, + }), + write_mask: wgpu::ColorWrites::ALL, + }], + }), + primitive: wgpu::PrimitiveState::default(), + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + }) +} diff --git a/examples/gui/platform/src/graphics/lowlevel/quad.rs b/examples/gui/platform/src/graphics/lowlevel/quad.rs new file mode 100644 index 0000000000..9c1fd85ae6 --- /dev/null +++ b/examples/gui/platform/src/graphics/lowlevel/quad.rs @@ -0,0 +1,31 @@ + + +/// A polygon with 4 corners +#[derive(Copy, Clone)] +pub struct Quad { + pub pos: [f32; 2], + pub width: f32, + pub height: f32, + pub color: [f32; 4], + pub border_color: [f32; 4], + pub border_width: f32, +} + +unsafe impl bytemuck::Pod for Quad {} +unsafe impl bytemuck::Zeroable for Quad {} + +impl Quad { + pub const SIZE: wgpu::BufferAddress = std::mem::size_of::() as wgpu::BufferAddress; + pub const DESC: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout { + array_stride: Self::SIZE, + step_mode: wgpu::VertexStepMode::Instance, + attributes: &wgpu::vertex_attr_array!( + 1 => Float32x2, + 2 => Float32, + 3 => Float32, + 4 => Float32x4, + 5 => Float32x4, + 6 => Float32, + ), + }; +} \ No newline at end of file diff --git a/examples/gui/platform/src/graphics/lowlevel/vertex.rs b/examples/gui/platform/src/graphics/lowlevel/vertex.rs new file mode 100644 index 0000000000..aa45bb7fb7 --- /dev/null +++ b/examples/gui/platform/src/graphics/lowlevel/vertex.rs @@ -0,0 +1,35 @@ +// Inspired by https://github.com/sotrh/learn-wgpu +// by Benjamin Hansen - license information can be found in the LEGAL_DETAILS +// file in the root directory of this distribution. +// +// Thank you, Benjamin! + +// Inspired by https://github.com/iced-rs/iced/blob/adce9e04213803bd775538efddf6e7908d1c605e/wgpu/src/shader/quad.wgsl +// By Héctor Ramón, Iced contributors Licensed under the MIT license. +// The license is included in the LEGAL_DETAILS file in the root directory of this distribution. + +// Thank you Héctor Ramón and Iced contributors! +use bytemuck::{Pod, Zeroable}; + + +#[repr(C)] +#[derive(Copy, Clone, Zeroable, Pod)] +pub struct Vertex { + pub _position: [f32; 2], +} + +impl Vertex { + pub const SIZE: wgpu::BufferAddress = std::mem::size_of::() as wgpu::BufferAddress; + pub const DESC: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout { + array_stride: Self::SIZE, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &[ + // position + wgpu::VertexAttribute { + offset: 0, + shader_location: 0, + format: wgpu::VertexFormat::Float32x2, + }, + ], + }; +} diff --git a/examples/gui/platform/src/graphics/mod.rs b/examples/gui/platform/src/graphics/mod.rs new file mode 100644 index 0000000000..0eb7fcd6da --- /dev/null +++ b/examples/gui/platform/src/graphics/mod.rs @@ -0,0 +1,4 @@ +pub mod colors; +pub mod lowlevel; +pub mod primitives; +pub mod style; diff --git a/examples/gui/platform/src/graphics/primitives/mod.rs b/examples/gui/platform/src/graphics/primitives/mod.rs new file mode 100644 index 0000000000..a9adb18862 --- /dev/null +++ b/examples/gui/platform/src/graphics/primitives/mod.rs @@ -0,0 +1,2 @@ +pub mod rect; +pub mod text; diff --git a/examples/gui/platform/src/graphics/primitives/rect.rs b/examples/gui/platform/src/graphics/primitives/rect.rs new file mode 100644 index 0000000000..8183fc6f7a --- /dev/null +++ b/examples/gui/platform/src/graphics/primitives/rect.rs @@ -0,0 +1,27 @@ +use crate::graphics::colors::Rgba; +use cgmath::Vector2; + +#[derive(Debug, Copy, Clone)] +pub struct RectElt { + pub rect: Rect, + pub color: Rgba, + pub border_width: f32, + pub border_color: Rgba, +} + +/// These fields are ordered this way because in Roc, the corresponding stuct is: +/// +/// { top : F32, left : F32, width : F32, height : F32 } +/// +/// alphabetically, that's { height, left, top, width } - which works out to the same as: +/// +/// struct Rect { height: f32, pos: Vector2, width: f32 } +/// +/// ...because Vector2 is a repr(C) struct of { x: f32, y: f32 } +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct Rect { + pub height: f32, + pub pos: Vector2, + pub width: f32, +} diff --git a/examples/gui/platform/src/graphics/primitives/text.rs b/examples/gui/platform/src/graphics/primitives/text.rs new file mode 100644 index 0000000000..f002d506e7 --- /dev/null +++ b/examples/gui/platform/src/graphics/primitives/text.rs @@ -0,0 +1,137 @@ +// Adapted from https://github.com/sotrh/learn-wgpu +// by Benjamin Hansen - license information can be found in the COPYRIGHT +// file in the root directory of this distribution. +// +// Thank you, Benjamin! + +use crate::graphics::colors::Rgba; +use crate::graphics::style::DEFAULT_FONT_SIZE; +use ab_glyph::{FontArc, Glyph, InvalidFont}; +use cgmath::{Vector2, Vector4}; +use glyph_brush::OwnedSection; +use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, Section}; + +use super::rect::Rect; + +#[derive(Debug)] +pub struct Text<'a> { + pub position: Vector2, + pub area_bounds: Vector2, + pub color: Rgba, + pub text: &'a str, + pub size: f32, + pub visible: bool, + pub centered: bool, +} + +impl<'a> Default for Text<'a> { + fn default() -> Self { + Self { + position: (0.0, 0.0).into(), + area_bounds: (std::f32::INFINITY, std::f32::INFINITY).into(), + color: Rgba::WHITE, + text: "", + size: DEFAULT_FONT_SIZE, + visible: true, + centered: false, + } + } +} + +pub fn layout_from_text(text: &Text) -> wgpu_glyph::Layout { + wgpu_glyph::Layout::default().h_align(if text.centered { + wgpu_glyph::HorizontalAlign::Center + } else { + wgpu_glyph::HorizontalAlign::Left + }) +} + +fn section_from_text<'a>( + text: &'a Text, + layout: wgpu_glyph::Layout, +) -> wgpu_glyph::Section<'a> { + Section { + screen_position: text.position.into(), + bounds: text.area_bounds.into(), + layout, + ..Section::default() + } + .add_text( + wgpu_glyph::Text::new(text.text) + .with_color(text.color) + .with_scale(text.size), + ) +} + +pub fn owned_section_from_text(text: &Text) -> OwnedSection { + let layout = layout_from_text(text); + + OwnedSection { + screen_position: text.position.into(), + bounds: text.area_bounds.into(), + layout, + ..OwnedSection::default() + } + .add_text( + glyph_brush::OwnedText::new(text.text) + .with_color(Vector4::from(text.color)) + .with_scale(text.size), + ) +} + +pub fn owned_section_from_glyph_texts( + text: Vec, + screen_position: (f32, f32), + area_bounds: (f32, f32), + layout: wgpu_glyph::Layout, +) -> glyph_brush::OwnedSection { + glyph_brush::OwnedSection { + screen_position, + bounds: area_bounds, + layout, + text, + } +} + +pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) { + let layout = layout_from_text(text); + + let section = section_from_text(text, layout); + + glyph_brush.queue(section.clone()); +} + +fn glyph_to_rect(glyph: &wgpu_glyph::SectionGlyph) -> Rect { + let position = glyph.glyph.position; + let px_scale = glyph.glyph.scale; + let width = glyph_width(&glyph.glyph); + let height = px_scale.y; + let top_y = glyph_top_y(&glyph.glyph); + + Rect { + pos: [position.x, top_y].into(), + width, + height, + } +} + +pub fn glyph_top_y(glyph: &Glyph) -> f32 { + let height = glyph.scale.y; + + glyph.position.y - height * 0.75 +} + +pub fn glyph_width(glyph: &Glyph) -> f32 { + glyph.scale.x * 0.4765 +} + +pub fn build_glyph_brush( + gpu_device: &wgpu::Device, + render_format: wgpu::TextureFormat, +) -> Result, InvalidFont> { + let inconsolata = FontArc::try_from_slice(include_bytes!( + "../../../../../../editor/Inconsolata-Regular.ttf" + ))?; + + Ok(GlyphBrushBuilder::using_font(inconsolata).build(gpu_device, render_format)) +} diff --git a/examples/gui/platform/src/graphics/shaders/quad.wgsl b/examples/gui/platform/src/graphics/shaders/quad.wgsl new file mode 100644 index 0000000000..a561e2fc24 --- /dev/null +++ b/examples/gui/platform/src/graphics/shaders/quad.wgsl @@ -0,0 +1,60 @@ + + +struct Globals { + ortho: mat4x4; +}; + +@group(0) +@binding(0) +var globals: Globals; + +struct VertexInput { + @location(0) position: vec2; +}; + +struct Quad { + @location(1) pos: vec2; // can't use the name "position" twice for compatibility with metal on MacOS + @location(2) width: f32; + @location(3) height: f32; + @location(4) color: vec4; + @location(5) border_color: vec4; + @location(6) border_width: f32; +}; + +struct VertexOutput { + @builtin(position) position: vec4; + @location(0) color: vec4; + @location(1) border_color: vec4; + @location(2) border_width: f32; +}; + +@stage(vertex) +fn vs_main( + input: VertexInput, + quad: Quad +) -> VertexOutput { + + var transform: mat4x4 = mat4x4( + vec4(quad.width, 0.0, 0.0, 0.0), + vec4(0.0, quad.height, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(quad.pos, 0.0, 1.0) + ); + + var out: VertexOutput; + + out.position = globals.ortho * transform * vec4(input.position, 0.0, 1.0);; + out.color = quad.color; + out.border_color = quad.border_color; + out.border_width = quad.border_width; + + return out; +} + + +@stage(fragment) +fn fs_main( + input: VertexOutput +) -> @location(0) vec4 { + return input.color; +} diff --git a/examples/gui/platform/src/graphics/style.rs b/examples/gui/platform/src/graphics/style.rs new file mode 100644 index 0000000000..11e609075b --- /dev/null +++ b/examples/gui/platform/src/graphics/style.rs @@ -0,0 +1 @@ +pub const DEFAULT_FONT_SIZE: f32 = 30.0; diff --git a/examples/gui/platform/src/gui.rs b/examples/gui/platform/src/gui.rs new file mode 100644 index 0000000000..0e6bc8b24b --- /dev/null +++ b/examples/gui/platform/src/gui.rs @@ -0,0 +1,650 @@ +use crate::{ + graphics::{ + colors::Rgba, + lowlevel::buffer::create_rect_buffers, + lowlevel::{buffer::MAX_QUADS, ortho::update_ortho_buffer}, + lowlevel::{buffer::QUAD_INDICES, pipelines}, + primitives::{ + rect::{Rect, RectElt}, + text::build_glyph_brush, + }, + }, + roc::{RocElem, RocElemTag}, +}; +use cgmath::{Vector2, Vector4}; +use glyph_brush::OwnedSection; +use pipelines::RectResources; +use roc_std::RocStr; +use std::error::Error; +use wgpu::{CommandEncoder, LoadOp, RenderPass, TextureView}; +use wgpu_glyph::{GlyphBrush, GlyphCruncher}; +use winit::{ + dpi::PhysicalSize, + event, + event::{Event, ModifiersState}, + event_loop::ControlFlow, + platform::run_return::EventLoopExtRunReturn, +}; + +// Inspired by: +// https://github.com/sotrh/learn-wgpu by Benjamin Hansen, which is licensed under the MIT license +// https://github.com/cloudhead/rgx by Alexis Sellier, which is licensed under the MIT license +// +// See this link to learn wgpu: https://sotrh.github.io/learn-wgpu/ + +fn run_event_loop(title: &str, root: RocElem) -> Result<(), Box> { + // Open window and create a surface + let mut event_loop = winit::event_loop::EventLoop::new(); + + let window = winit::window::WindowBuilder::new() + .with_inner_size(PhysicalSize::new(1900.0, 1000.0)) + .with_title(title) + .build(&event_loop) + .unwrap(); + + let instance = wgpu::Instance::new(wgpu::Backends::all()); + + let surface = unsafe { instance.create_surface(&window) }; + + // Initialize GPU + let (gpu_device, cmd_queue) = futures::executor::block_on(async { + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::HighPerformance, + compatible_surface: Some(&surface), + force_fallback_adapter: false, + }) + .await + .expect(r#"Request adapter + If you're running this from inside nix, follow the instructions here to resolve this: https://github.com/rtfeldman/roc/blob/trunk/BUILDING_FROM_SOURCE.md#editor + "#); + + adapter + .request_device( + &wgpu::DeviceDescriptor { + label: None, + features: wgpu::Features::empty(), + limits: wgpu::Limits::default(), + }, + None, + ) + .await + .expect("Request device") + }); + + // Create staging belt and a local pool + let mut staging_belt = wgpu::util::StagingBelt::new(1024); + let mut local_pool = futures::executor::LocalPool::new(); + let local_spawner = local_pool.spawner(); + + // Prepare swap chain + let render_format = wgpu::TextureFormat::Bgra8Unorm; + let mut size = window.inner_size(); + + let surface_config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: render_format, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Mailbox, + }; + + surface.configure(&gpu_device, &surface_config); + + let rect_resources = pipelines::make_rect_pipeline(&gpu_device, &surface_config); + + let mut glyph_brush = build_glyph_brush(&gpu_device, render_format)?; + + let is_animating = true; + + let mut keyboard_modifiers = ModifiersState::empty(); + + // Render loop + window.request_redraw(); + + event_loop.run_return(|event, _, control_flow| { + // TODO dynamically switch this on/off depending on whether any + // animations are running. Should conserve CPU usage and battery life! + if is_animating { + *control_flow = ControlFlow::Poll; + } else { + *control_flow = ControlFlow::Wait; + } + + match event { + //Close + Event::WindowEvent { + event: event::WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + //Resize + Event::WindowEvent { + event: event::WindowEvent::Resized(new_size), + .. + } => { + size = new_size; + + surface.configure( + &gpu_device, + &wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: render_format, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Mailbox, + }, + ); + + update_ortho_buffer( + size.width, + size.height, + &gpu_device, + &rect_resources.ortho.buffer, + &cmd_queue, + ); + } + //Received Character + Event::WindowEvent { + event: event::WindowEvent::ReceivedCharacter(_ch), + .. + } => { + // let input_outcome_res = + // app_update::handle_new_char(&ch, &mut app_model, keyboard_modifiers); + // if let Err(e) = input_outcome_res { + // print_err(&e) + // } else if let Ok(InputOutcome::Ignored) = input_outcome_res { + // println!("Input '{}' ignored!", ch); + // } + todo!("TODO handle character input"); + } + //Keyboard Input + Event::WindowEvent { + event: event::WindowEvent::KeyboardInput { input: _, .. }, + .. + } => { + // if let Some(virtual_keycode) = input.virtual_keycode { + // if let Some(ref mut ed_model) = app_model.ed_model_opt { + // if ed_model.has_focus { + // let keydown_res = keyboard_input::handle_keydown( + // input.state, + // virtual_keycode, + // keyboard_modifiers, + // &mut app_model, + // ); + + // if let Err(e) = keydown_res { + // print_err(&e) + // } + // } + // } + // } + todo!("TODO handle keyboard input"); + } + //Modifiers Changed + Event::WindowEvent { + event: event::WindowEvent::ModifiersChanged(modifiers), + .. + } => { + keyboard_modifiers = modifiers; + } + Event::MainEventsCleared => window.request_redraw(), + Event::RedrawRequested { .. } => { + // Get a command cmd_encoder for the current frame + let mut cmd_encoder = + gpu_device.create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Redraw"), + }); + + let surface_texture = surface + .get_current_texture() + .expect("Failed to acquire next SwapChainTexture"); + + let view = surface_texture + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + + // for text_section in &rects_and_texts.text_sections_behind { + // let borrowed_text = text_section.to_borrowed(); + + // glyph_brush.queue(borrowed_text); + // } + + // draw first layer of text + // glyph_brush + // .draw_queued( + // &gpu_device, + // &mut staging_belt, + // &mut cmd_encoder, + // &view, + // size.width, + // size.height, + // ) + // .expect("Failed to draw first layer of text."); + + // draw rects on top of first text layer + // draw_rects( + // &rects_and_texts.rects_front, + // &mut cmd_encoder, + // &view, + // &gpu_device, + // &rect_resources, + // wgpu::LoadOp::Load, + // ); + + // TODO use with_capacity based on some heuristic + let (_bounds, drawable) = to_drawable( + &root, + Bounds { + width: size.width as f32, + height: size.height as f32, + }, + &mut glyph_brush, + ); + + process_drawable( + drawable, + &mut staging_belt, + &mut glyph_brush, + &mut cmd_encoder, + &view, + &gpu_device, + &rect_resources, + wgpu::LoadOp::Load, + Bounds { + width: size.width as f32, + height: size.height as f32, + }, + ); + + // for text_section in &rects_and_texts.text_sections_front { + // let borrowed_text = text_section.to_borrowed(); + + // glyph_brush.queue(borrowed_text); + // } + + // draw text + // glyph_brush + // .draw_queued( + // &gpu_device, + // &mut staging_belt, + // &mut cmd_encoder, + // &view, + // size.width, + // size.height, + // ) + // .expect("Failed to draw queued text."); + + staging_belt.finish(); + cmd_queue.submit(Some(cmd_encoder.finish())); + surface_texture.present(); + + // Recall unused staging buffers + use futures::task::SpawnExt; + + local_spawner + .spawn(staging_belt.recall()) + .expect("Recall staging belt"); + + local_pool.run_until_stalled(); + } + _ => { + *control_flow = winit::event_loop::ControlFlow::Wait; + } + } + }); + + Ok(()) +} + +fn draw_rects( + all_rects: &[RectElt], + cmd_encoder: &mut CommandEncoder, + texture_view: &TextureView, + gpu_device: &wgpu::Device, + rect_resources: &RectResources, + load_op: LoadOp, +) { + let rect_buffers = create_rect_buffers(gpu_device, cmd_encoder, all_rects); + + let mut render_pass = begin_render_pass(cmd_encoder, texture_view, load_op); + + render_pass.set_pipeline(&rect_resources.pipeline); + render_pass.set_bind_group(0, &rect_resources.ortho.bind_group, &[]); + + render_pass.set_vertex_buffer(0, rect_buffers.vertex_buffer.slice(..)); + render_pass.set_vertex_buffer(1, rect_buffers.quad_buffer.slice(..)); + + render_pass.set_index_buffer( + rect_buffers.index_buffer.slice(..), + wgpu::IndexFormat::Uint16, + ); + + render_pass.draw_indexed(0..QUAD_INDICES.len() as u32, 0, 0..MAX_QUADS as u32); +} + +fn begin_render_pass<'a>( + cmd_encoder: &'a mut CommandEncoder, + texture_view: &'a TextureView, + load_op: LoadOp, +) -> RenderPass<'a> { + cmd_encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachment { + view: texture_view, + resolve_target: None, + ops: wgpu::Operations { + load: load_op, + store: true, + }, + }], + depth_stencil_attachment: None, + label: None, + }) +} + +pub fn render(title: RocStr, root: RocElem) { + run_event_loop(title.as_str(), root).expect("Error running event loop"); +} + +#[derive(Copy, Clone, Debug, Default)] +struct Bounds { + width: f32, + height: f32, +} + +#[derive(Clone, Debug)] +struct Drawable { + bounds: Bounds, + content: DrawableContent, +} + +#[derive(Clone, Debug)] +enum DrawableContent { + /// This stores an actual Section because an earlier step needs to know the bounds of + /// the text, and making a Section is a convenient way to compute those bounds. + Text(OwnedSection, Vector2), + FillRect { + color: Rgba, + border_width: f32, + border_color: Rgba, + }, + Multi(Vec), + Offset(Vec<(Vector2, Drawable)>), +} + +fn process_drawable( + drawable: Drawable, + staging_belt: &mut wgpu::util::StagingBelt, + glyph_brush: &mut GlyphBrush<()>, + cmd_encoder: &mut CommandEncoder, + texture_view: &TextureView, + gpu_device: &wgpu::Device, + rect_resources: &RectResources, + load_op: LoadOp, + texture_size: Bounds, +) { + // TODO iterate through drawables, + // calculating a pos using offset, + // calling draw and updating bounding boxes + let pos: Vector2 = (0.0, 0.0).into(); + + draw( + drawable.bounds, + drawable.content, + pos, + staging_belt, + glyph_brush, + cmd_encoder, + texture_view, + gpu_device, + rect_resources, + load_op, + texture_size, + ); +} + +fn draw( + bounds: Bounds, + content: DrawableContent, + pos: Vector2, + staging_belt: &mut wgpu::util::StagingBelt, + glyph_brush: &mut GlyphBrush<()>, + cmd_encoder: &mut CommandEncoder, + texture_view: &TextureView, + gpu_device: &wgpu::Device, + rect_resources: &RectResources, + load_op: LoadOp, + texture_size: Bounds, +) { + use DrawableContent::*; + + match content { + Text(section, offset) => { + glyph_brush.queue(section.with_screen_position(pos + offset).to_borrowed()); + + glyph_brush + .draw_queued( + gpu_device, + staging_belt, + cmd_encoder, + texture_view, + texture_size.width as u32, // TODO why do we make these be u32 and then cast to f32 in orthorgraphic_projection? + texture_size.height as u32, + ) + .expect("Failed to draw text element"); + } + FillRect { + color, + border_width, + border_color, + } => { + // TODO store all these colors and things in FillRect + let rect_elt = RectElt { + rect: Rect { + pos, + width: bounds.width, + height: bounds.height, + }, + color, + border_width, + border_color, + }; + + // TODO inline draw_rects into here! + draw_rects( + &[rect_elt], + cmd_encoder, + texture_view, + gpu_device, + rect_resources, + load_op, + ); + } + Offset(children) => { + for (offset, child) in children.into_iter() { + draw( + child.bounds, + child.content, + pos + offset, + staging_belt, + glyph_brush, + cmd_encoder, + texture_view, + gpu_device, + rect_resources, + load_op, + texture_size, + ); + } + } + Multi(children) => { + for child in children.into_iter() { + draw( + child.bounds, + child.content, + pos, + staging_belt, + glyph_brush, + cmd_encoder, + texture_view, + gpu_device, + rect_resources, + load_op, + texture_size, + ); + } + } + } +} + +fn to_drawable( + elem: &RocElem, + bounds: Bounds, + glyph_brush: &mut GlyphBrush<()>, +) -> (Bounds, Drawable) { + use RocElemTag::*; + + match elem.tag() { + Button => { + let button = unsafe { &elem.entry().button }; + let styles = button.styles; + let (child_bounds, child_drawable) = to_drawable(&*button.child, bounds, glyph_brush); + + let button_drawable = Drawable { + bounds: child_bounds, + content: DrawableContent::FillRect { + color: styles.bg_color, + border_width: styles.border_width, + border_color: styles.border_color, + }, + }; + + let drawable = Drawable { + bounds: child_bounds, + content: DrawableContent::Multi(vec![button_drawable, child_drawable]), + }; + + (child_bounds, drawable) + } + Text => { + // TODO let text color and font settings inherit from parent + let text = unsafe { &elem.entry().text }; + let is_centered = true; // TODO don't hardcode this + let layout = wgpu_glyph::Layout::default().h_align(if is_centered { + wgpu_glyph::HorizontalAlign::Center + } else { + wgpu_glyph::HorizontalAlign::Left + }); + + let section = owned_section_from_str(text.as_str(), bounds, layout); + + // Calculate the bounds and offset by measuring glyphs + let text_bounds; + let offset; + + match glyph_brush.glyph_bounds(section.to_borrowed()) { + Some(glyph_bounds) => { + text_bounds = Bounds { + width: glyph_bounds.max.x - glyph_bounds.min.x, + height: glyph_bounds.max.y - glyph_bounds.min.y, + }; + + offset = (-glyph_bounds.min.x, -glyph_bounds.min.y).into(); + } + None => { + text_bounds = Bounds { + width: 0.0, + height: 0.0, + }; + + offset = (0.0, 0.0).into(); + } + } + + let drawable = Drawable { + bounds: text_bounds, + content: DrawableContent::Text(section, offset), + }; + + (text_bounds, drawable) + } + Row => { + let row = unsafe { &elem.entry().row_or_col }; + let mut final_bounds = Bounds::default(); + let mut offset: Vector2 = (0.0, 0.0).into(); + let mut offset_entries = Vec::with_capacity(row.children.len()); + + for child in row.children.as_slice().iter() { + let (child_bounds, child_drawable) = to_drawable(&child, bounds, glyph_brush); + + offset_entries.push((offset, child_drawable)); + + // Make sure the final height is enough to fit this child + final_bounds.height = final_bounds.height.max(child_bounds.height); + + // Add the child's width to the final width + final_bounds.width = final_bounds.width + child_bounds.width; + + // Offset the next child to make sure it appears after this one. + offset.x += child_bounds.width; + } + + ( + final_bounds, + Drawable { + bounds: final_bounds, + content: DrawableContent::Offset(offset_entries), + }, + ) + } + Col => { + let col = unsafe { &elem.entry().row_or_col }; + let mut final_bounds = Bounds::default(); + let mut offset: Vector2 = (0.0, 0.0).into(); + let mut offset_entries = Vec::with_capacity(col.children.len()); + + for child in col.children.as_slice().iter() { + let (child_bounds, child_drawable) = to_drawable(&child, bounds, glyph_brush); + + offset_entries.push((offset, child_drawable)); + + // Make sure the final width is enough to fit this child + final_bounds.width = final_bounds.width.max(child_bounds.width); + + // Add the child's height to the final height + final_bounds.height = final_bounds.height + child_bounds.height; + + // Offset the next child to make sure it appears after this one. + offset.y += child_bounds.height; + } + + ( + final_bounds, + Drawable { + bounds: final_bounds, + content: DrawableContent::Offset(offset_entries), + }, + ) + } + } +} + +fn owned_section_from_str( + string: &str, + bounds: Bounds, + layout: wgpu_glyph::Layout, +) -> OwnedSection { + // TODO don't hardcode any of this! + let color = Rgba::WHITE; + let size: f32 = 40.0; + + OwnedSection { + bounds: (bounds.width, bounds.height), + layout, + ..OwnedSection::default() + } + .add_text( + glyph_brush::OwnedText::new(string) + .with_color(Vector4::from(color)) + .with_scale(size), + ) +} diff --git a/examples/gui/platform/src/lib.rs b/examples/gui/platform/src/lib.rs new file mode 100644 index 0000000000..17fa0b4d4a --- /dev/null +++ b/examples/gui/platform/src/lib.rs @@ -0,0 +1,21 @@ +mod graphics; +mod gui; +mod rects_and_texts; +mod roc; + +use crate::roc::RocElem; + +extern "C" { + #[link_name = "roc__renderForHost_1_exposed"] + fn roc_render() -> RocElem; +} + +#[no_mangle] +pub extern "C" fn rust_main() -> i32 { + let root_elem = unsafe { roc_render() }; + + gui::render("test title".into(), root_elem); + + // Exit code + 0 +} diff --git a/examples/gui/platform/src/main.rs b/examples/gui/platform/src/main.rs new file mode 100644 index 0000000000..51175f934b --- /dev/null +++ b/examples/gui/platform/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + std::process::exit(host::rust_main()); +} diff --git a/examples/gui/platform/src/rects_and_texts.rs b/examples/gui/platform/src/rects_and_texts.rs new file mode 100644 index 0000000000..3eed8654ac --- /dev/null +++ b/examples/gui/platform/src/rects_and_texts.rs @@ -0,0 +1,70 @@ +use crate::graphics::primitives::rect::RectElt; +use crate::graphics::primitives::text::{owned_section_from_text, Text}; + +#[derive(Debug)] +pub struct RectsAndTexts { + pub text_sections_behind: Vec, // displayed in front of rect_behind, behind everything else + pub text_sections_front: Vec, // displayed in front of everything + pub rects_behind: Vec, // displayed at lowest depth + pub rects_front: Vec, // displayed in front of text_sections_behind, behind text_sections_front +} + +impl RectsAndTexts { + pub fn new() -> Self { + Self { + text_sections_behind: Vec::new(), + text_sections_front: Vec::new(), + rects_behind: Vec::new(), + rects_front: Vec::new(), + } + } + + pub fn init( + rects_behind: Vec, + texts_behind: Vec, + rects_front: Vec, + texts_front: Vec, + ) -> Self { + Self { + text_sections_behind: texts_behind + .iter() + .map(|txt| owned_section_from_text(txt)) + .collect(), + text_sections_front: texts_front + .iter() + .map(|txt| owned_section_from_text(txt)) + .collect(), + rects_behind, + rects_front, + } + } + + pub fn add_text_behind(&mut self, new_text_section: glyph_brush::OwnedSection) { + self.text_sections_behind.push(new_text_section); + } + + pub fn add_text_front(&mut self, new_text_section: glyph_brush::OwnedSection) { + self.text_sections_front.push(new_text_section); + } + + pub fn add_rect_behind(&mut self, new_rect: RectElt) { + self.rects_behind.push(new_rect); + } + + pub fn add_rects_behind(&mut self, new_rects: Vec) { + self.rects_behind.extend(new_rects); + } + + pub fn add_rect_front(&mut self, new_rect: RectElt) { + self.rects_front.push(new_rect); + } + + pub fn extend(&mut self, rects_and_texts: RectsAndTexts) { + self.text_sections_behind + .extend(rects_and_texts.text_sections_behind); + self.text_sections_front + .extend(rects_and_texts.text_sections_front); + self.rects_behind.extend(rects_and_texts.rects_behind); + self.rects_front.extend(rects_and_texts.rects_front); + } +} diff --git a/examples/gui/platform/src/roc.rs b/examples/gui/platform/src/roc.rs new file mode 100644 index 0000000000..034181deed --- /dev/null +++ b/examples/gui/platform/src/roc.rs @@ -0,0 +1,150 @@ +use crate::graphics::colors::Rgba; +use core::ffi::c_void; +use core::mem::{self, ManuallyDrop}; +use roc_std::{ReferenceCount, RocList, RocStr}; +use std::ffi::CStr; +use std::os::raw::c_char; + +#[no_mangle] +pub unsafe extern "C" fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void { + return libc::malloc(size); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_realloc( + c_ptr: *mut c_void, + new_size: usize, + _old_size: usize, + _alignment: u32, +) -> *mut c_void { + return libc::realloc(c_ptr, new_size); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { + return libc::free(c_ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) { + match tag_id { + 0 => { + let slice = CStr::from_ptr(c_ptr as *const c_char); + let string = slice.to_str().unwrap(); + eprintln!("Roc hit a panic: {}", string); + std::process::exit(1); + } + _ => todo!(), + } +} + +#[no_mangle] +pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void { + libc::memcpy(dst, src, n) +} + +#[no_mangle] +pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void { + libc::memset(dst, c, n) +} + +#[repr(transparent)] +#[cfg(target_pointer_width = "64")] // on a 64-bit system, the tag fits in this pointer's spare 3 bits +pub struct RocElem { + entry: *const RocElemEntry, +} + +impl RocElem { + #[cfg(target_pointer_width = "64")] + pub fn tag(&self) -> RocElemTag { + // On a 64-bit system, the last 3 bits of the pointer store the tag + unsafe { mem::transmute::((self.entry as u8) & 0b0000_0111) } + } + + pub fn entry(&self) -> &RocElemEntry { + // On a 64-bit system, the last 3 bits of the pointer store the tag + let cleared = self.entry as usize & !0b111; + + unsafe { &*(cleared as *const RocElemEntry) } + } +} + +#[repr(u8)] +#[allow(unused)] // This is actually used, just via a mem::transmute from u8 +#[derive(Debug, Clone, Copy)] +pub enum RocElemTag { + Button = 0, + Col, + Row, + Text, +} + +#[repr(C)] +pub struct RocButton { + pub child: ManuallyDrop, + pub styles: ButtonStyles, +} + +#[repr(C)] +pub struct RocRowOrCol { + pub children: RocList, +} + +unsafe impl ReferenceCount for RocElem { + /// Increment the reference count. + fn increment(&self) { + use RocElemTag::*; + + match self.tag() { + Button => unsafe { &*self.entry().button.child }.increment(), + Text => unsafe { &*self.entry().text }.increment(), + Row | Col => { + let children = unsafe { &self.entry().row_or_col.children }; + + for child in children.as_slice().iter() { + child.increment(); + } + } + } + } + + /// Decrement the reference count. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` points to a value with a non-zero + /// reference count. + unsafe fn decrement(ptr: *const Self) { + use RocElemTag::*; + + let elem = &*ptr; + + match elem.tag() { + Button => ReferenceCount::decrement(&*elem.entry().button.child), + Text => ReferenceCount::decrement(&*elem.entry().text), + Row | Col => { + let children = &elem.entry().row_or_col.children; + + for child in children.as_slice().iter() { + ReferenceCount::decrement(child); + } + } + } + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct ButtonStyles { + pub bg_color: Rgba, + pub border_color: Rgba, + pub border_width: f32, + pub text_color: Rgba, +} + +#[repr(C)] +pub union RocElemEntry { + pub button: ManuallyDrop, + pub text: ManuallyDrop, + pub row_or_col: ManuallyDrop, +} diff --git a/linker/Cargo.toml b/linker/Cargo.toml index 39cfdcdd37..7543f9438b 100644 --- a/linker/Cargo.toml +++ b/linker/Cargo.toml @@ -19,10 +19,10 @@ bench = false [dependencies] roc_mono = { path = "../compiler/mono" } -roc_build = { path = "../compiler/build", default-features = false } +roc_build = { path = "../compiler/build" } roc_collections = { path = "../compiler/collections" } bumpalo = { version = "3.8.0", features = ["collections"] } -clap = { version = "= 3.0.0-beta.5", default-features = false, features = ["std", "color", "suggestions"] } +clap = { version = "3.0.0-beta.5", default-features = false, features = ["std", "color", "suggestions"] } iced-x86 = { version = "1.15.0", default-features = false, features = ["std", "decoder", "op_code_info", "instr_info"] } memmap2 = "0.5.0" object = { version = "0.26.2", features = ["read", "write"] } diff --git a/repl_cli/Cargo.toml b/repl_cli/Cargo.toml index 240d7113ba..1ae373c4d5 100644 --- a/repl_cli/Cargo.toml +++ b/repl_cli/Cargo.toml @@ -5,16 +5,25 @@ version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +# pipe target to roc_build +target-arm = ["roc_build/target-arm"] +target-aarch64 = ["roc_build/target-aarch64"] +target-x86 = ["roc_build/target-x86"] +target-x86_64 = ["roc_build/target-x86_64"] +target-wasm32 = ["roc_build/target-wasm32"] + [dependencies] -bumpalo = {version = "3.8.0", features = ["collections"]} +bumpalo = { version = "3.8.0", features = ["collections"] } const_format = "0.2.22" inkwell = {path = "../vendor/inkwell"} -libloading = {version = "0.7.1"} +libloading = "0.7.1" rustyline = {git = "https://github.com/rtfeldman/rustyline", tag = "v9.1.1"} rustyline-derive = {git = "https://github.com/rtfeldman/rustyline", tag = "v9.1.1"} target-lexicon = "0.12.2" -roc_build = {path = "../compiler/build"} +# TODO: make llvm optional +roc_build = {path = "../compiler/build", features = ["llvm"]} roc_collections = {path = "../compiler/collections"} roc_gen_llvm = {path = "../compiler/gen_llvm"} roc_load = {path = "../compiler/load"} diff --git a/repl_eval/Cargo.toml b/repl_eval/Cargo.toml index 562cb27c9e..ebb3843553 100644 --- a/repl_eval/Cargo.toml +++ b/repl_eval/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bumpalo = {version = "3.8.0", features = ["collections"]} +bumpalo = { version = "3.8.0", features = ["collections"] } roc_builtins = {path = "../compiler/builtins"} roc_can = {path = "../compiler/can"} diff --git a/repl_eval/src/eval.rs b/repl_eval/src/eval.rs index 483d7b6be6..4ec51afef4 100644 --- a/repl_eval/src/eval.rs +++ b/repl_eval/src/eval.rs @@ -5,11 +5,11 @@ use std::cmp::{max_by_key, min_by_key}; use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_collections::all::MutMap; use roc_module::called_via::CalledVia; -use roc_module::ident::TagName; +use roc_module::ident::{Lowercase, TagName}; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_mono::ir::ProcLayout; use roc_mono::layout::{ - union_sorted_tags_help, Builtin, Layout, UnionLayout, UnionVariant, WrappedVariant, + union_sorted_tags_help, Builtin, Layout, LayoutCache, UnionLayout, UnionVariant, WrappedVariant, }; use roc_parse::ast::{AssignedField, Collection, Expr, StrLiteral}; use roc_region::all::{Loc, Region}; @@ -70,6 +70,7 @@ pub fn jit_to_ast<'a, A: ReplApp<'a>>( } } +#[derive(Debug)] enum NewtypeKind<'a> { Tag(&'a TagName), RecordField(&'a str), @@ -89,10 +90,11 @@ fn unroll_newtypes<'a>( mut content: &'a Content, ) -> (Vec<'a, NewtypeKind<'a>>, &'a Content) { let mut newtype_containers = Vec::with_capacity_in(1, env.arena); + let mut force_alias_content = None; loop { match content { Content::Structure(FlatType::TagUnion(tags, _)) - if tags.is_newtype_wrapper(env.subs) => + if tags.is_newtype_wrapper_of_global_tag(env.subs) => { let (tag_name, vars): (&TagName, &[Variable]) = tags .unsorted_iterator(env.subs, Variable::EMPTY_TAG_UNION) @@ -113,7 +115,20 @@ fn unroll_newtypes<'a>( let field_var = *field.as_inner(); content = env.subs.get_content_without_compacting(field_var); } - _ => return (newtype_containers, content), + Content::Alias(_, _, real_var) => { + // We need to pass through aliases too, because their underlying types may have + // unrolled newtypes. In such cases return the list of unrolled newtypes, but keep + // the content as the alias for readability. For example, + // T : { a : Str } + // v : T + // v = { a : "value" } + // v + // Here we need the newtype container to be `[RecordField(a)]`, but the content to + // remain as the alias `T`. + force_alias_content = Some(content); + content = env.subs.get_content_without_compacting(*real_var); + } + _ => return (newtype_containers, force_alias_content.unwrap_or(content)), } } } @@ -334,15 +349,11 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>( Layout::Struct { field_layouts, .. } => { let struct_addr_to_ast = |mem: &'a A::Memory, addr: usize| match content { Content::Structure(FlatType::Record(fields, _)) => { - Ok(struct_to_ast(env, mem, addr, field_layouts, *fields)) + Ok(struct_to_ast(env, mem, addr, *fields)) + } + Content::Structure(FlatType::EmptyRecord) => { + Ok(struct_to_ast(env, mem, addr, RecordFields::empty())) } - Content::Structure(FlatType::EmptyRecord) => Ok(struct_to_ast( - env, - mem, - addr, - field_layouts, - RecordFields::empty(), - )), Content::Structure(FlatType::TagUnion(tags, _)) => { debug_assert_eq!(tags.len(), 1); @@ -518,7 +529,7 @@ fn addr_to_ast<'a, M: ReplAppMemory>( } (_, Layout::Struct{field_layouts, ..}) => match content { Content::Structure(FlatType::Record(fields, _)) => { - struct_to_ast(env, mem, addr, field_layouts, *fields) + struct_to_ast(env, mem, addr, *fields) } Content::Structure(FlatType::TagUnion(tags, _)) => { debug_assert_eq!(tags.len(), 1); @@ -531,7 +542,7 @@ fn addr_to_ast<'a, M: ReplAppMemory>( single_tag_union_to_ast(env, mem, addr, field_layouts, tag_name, &[]) } Content::Structure(FlatType::EmptyRecord) => { - struct_to_ast(env, mem, addr, &[], RecordFields::empty()) + struct_to_ast(env, mem, addr, RecordFields::empty()) } other => { unreachable!( @@ -841,30 +852,46 @@ fn struct_to_ast<'a, M: ReplAppMemory>( env: &Env<'a, 'a>, mem: &'a M, addr: usize, - field_layouts: &'a [Layout<'a>], record_fields: RecordFields, ) -> Expr<'a> { let arena = env.arena; let subs = env.subs; - let mut output = Vec::with_capacity_in(field_layouts.len(), arena); + let mut output = Vec::with_capacity_in(record_fields.len(), arena); let sorted_fields: Vec<_> = Vec::from_iter_in( record_fields.sorted_iterator(env.subs, Variable::EMPTY_RECORD), - env.arena, + arena, ); + let mut layout_cache = LayoutCache::new(env.target_info); + // We recalculate the layouts here because we will have compiled the record so that its fields + // are sorted by descending alignment, and then alphabetic, but the type of the record is + // always only sorted alphabetically. We want to arrange the rendered record in the order of + // the type. + let field_to_layout: MutMap = sorted_fields + .iter() + .map(|(label, field)| { + let layout = layout_cache + .from_var(arena, *field.as_inner(), env.subs) + .unwrap(); + (label.clone(), layout) + }) + .collect(); + if sorted_fields.len() == 1 { // this is a 1-field wrapper record around another record or 1-tag tag union let (label, field) = sorted_fields.into_iter().next().unwrap(); let inner_content = env.subs.get_content_without_compacting(field.into_inner()); + debug_assert_eq!(field_to_layout.len(), 1); + let inner_layouts = arena.alloc([field_to_layout.into_values().next().unwrap()]); let loc_expr = &*arena.alloc(Loc { value: addr_to_ast( env, mem, addr, - &Layout::struct_no_name_order(field_layouts), + &Layout::struct_no_name_order(inner_layouts), WhenRecursive::Unreachable, inner_content, ), @@ -880,19 +907,20 @@ fn struct_to_ast<'a, M: ReplAppMemory>( region: Region::zero(), }; - let output = env.arena.alloc([loc_field]); + let output = arena.alloc([loc_field]); Expr::Record(Collection::with_items(output)) } else { - debug_assert_eq!(sorted_fields.len(), field_layouts.len()); + debug_assert_eq!(sorted_fields.len(), field_to_layout.len()); // We'll advance this as we iterate through the fields let mut field_addr = addr; - for ((label, field), field_layout) in sorted_fields.into_iter().zip(field_layouts.iter()) { + for (label, field) in sorted_fields.into_iter() { let var = field.into_inner(); let content = subs.get_content_without_compacting(var); + let field_layout = field_to_layout.get(&label).unwrap(); let loc_expr = &*arena.alloc(Loc { value: addr_to_ast( diff --git a/repl_test/src/tests.rs b/repl_test/src/tests.rs index d6e88e44c3..c24aa75b54 100644 --- a/repl_test/src/tests.rs +++ b/repl_test/src/tests.rs @@ -840,7 +840,7 @@ fn function_in_list() { fn function_in_record() { expect_success( r#"{ n: 1, adder: \x -> x + 1 }"#, - r#"{ adder: , n: } : { adder : Num a -> Num a, n : Num * }"#, + r#"{ adder: , n: 1 } : { adder : Num a -> Num a, n : Num * }"#, ) } @@ -975,3 +975,48 @@ fn issue_2343_complete_mono_with_shadowed_vars() { ), ); } + +#[test] +fn record_with_type_behind_alias() { + expect_success( + indoc!( + r#" + T : { a: Str } + v : T + v = { a: "value" } + v + "# + ), + r#"{ a: "value" } : T"#, + ); +} + +#[test] +fn tag_with_type_behind_alias() { + expect_success( + indoc!( + r#" + T : [ A Str ] + v : T + v = A "value" + v + "# + ), + r#"A "value" : T"#, + ); +} + +#[cfg(not(feature = "wasm"))] +#[test] +fn issue_2588_record_with_function_and_nonfunction() { + expect_success( + indoc!( + r#" + x = 1 + f = \n -> n * 2 + { y: f x, f } + "# + ), + r#"{ f: , y: 2 } : { f : Num a -> Num a, y : Num * }"#, + ) +} diff --git a/repl_wasm/Cargo.toml b/repl_wasm/Cargo.toml index 5e34c1b389..27f9ab6830 100644 --- a/repl_wasm/Cargo.toml +++ b/repl_wasm/Cargo.toml @@ -10,8 +10,8 @@ crate-type = ["cdylib"] roc_builtins = {path = "../compiler/builtins"} [dependencies] -bumpalo = {version = "3.8.0", features = ["collections"]} -futures = {version = "0.3.17", optional = true} +bumpalo = { version = "3.8.0", features = ["collections"] } +futures = { version = "0.3.17", optional = true } js-sys = "0.3.56" wasm-bindgen = "0.2.79" wasm-bindgen-futures = "0.4.29" diff --git a/reporting/src/error/canonicalize.rs b/reporting/src/error/canonicalize.rs index 3400a52dbf..351d2e9a23 100644 --- a/reporting/src/error/canonicalize.rs +++ b/reporting/src/error/canonicalize.rs @@ -945,13 +945,17 @@ fn pretty_runtime_error<'b>( } Unknown => " ", QualifiedIdentifier => " qualified ", + EmptySingleQuote => " empty character literal ", + MultipleCharsInSingleQuote => " overfull literal ", }; let tip = match problem { MalformedInt | MalformedFloat | MalformedBase(_) => alloc .tip() .append(alloc.reflow("Learn more about number literals at TODO")), - Unknown | BadIdent(_) => alloc.nil(), + EmptySingleQuote | MultipleCharsInSingleQuote | Unknown | BadIdent(_) => { + alloc.nil() + } QualifiedIdentifier => alloc.tip().append( alloc.reflow("In patterns, only private and global tags can be qualified"), ), @@ -1015,8 +1019,16 @@ fn pretty_runtime_error<'b>( module_name, imported_modules, region, + module_exists, } => { - doc = module_not_found(alloc, lines, region, &module_name, imported_modules); + doc = module_not_found( + alloc, + lines, + region, + &module_name, + imported_modules, + module_exists, + ); title = MODULE_NOT_IMPORTED; } @@ -1333,6 +1345,37 @@ fn pretty_runtime_error<'b>( title = MISSING_DEFINITION; } + RuntimeError::EmptySingleQuote(region) => { + let tip = alloc + .tip() + .append(alloc.reflow("Learn more about character literals at TODO")); + + doc = alloc.stack(vec![ + alloc.concat(vec![alloc.reflow("This character literal is empty.")]), + alloc.region(lines.convert_region(region)), + tip, + ]); + + title = SYNTAX_PROBLEM; + } + RuntimeError::MultipleCharsInSingleQuote(region) => { + let tip = alloc + .tip() + .append(alloc.reflow("Learn more about character literals at TODO")); + + doc = alloc.stack(vec![ + alloc.concat(vec![ + alloc.reflow("This character literal contains more than one code point.") + ]), + alloc.region(lines.convert_region(region)), + alloc.concat(vec![ + alloc.reflow("Character literals can only contain one code point.") + ]), + tip, + ]); + + title = SYNTAX_PROBLEM; + } RuntimeError::OpaqueNotDefined { usage: Loc { @@ -1501,34 +1544,39 @@ fn not_found<'b>( ]) } +/// Generate a message informing the user that a module was referenced, but not found +/// +/// See [`roc_problem::can::ModuleNotImported`] fn module_not_found<'b>( alloc: &'b RocDocAllocator<'b>, lines: &LineInfo, region: roc_region::all::Region, name: &ModuleName, options: MutSet>, + module_exists: bool, ) -> RocDocBuilder<'b> { - let mut suggestions = - suggest::sort(name.as_str(), options.iter().map(|v| v.as_ref()).collect()); - suggestions.truncate(4); + // If the module exists, sugguest that the user import it + let details = if module_exists { + // TODO: Maybe give an example of how to do that + alloc.reflow("Did you mean to import it?") + } else { + // If the module might not exist, sugguest that it's a typo + let mut suggestions = + suggest::sort(name.as_str(), options.iter().map(|v| v.as_ref()).collect()); + suggestions.truncate(4); - let default_no = alloc.concat(vec![ - alloc.reflow("Is there an "), - alloc.keyword("import"), - alloc.reflow(" or "), - alloc.keyword("exposing"), - alloc.reflow(" missing up-top"), - ]); - - let default_yes = alloc - .reflow("Is there an import missing? Perhaps there is a typo. Did you mean one of these?"); - - let to_details = |no_suggestion_details, yes_suggestion_details| { if suggestions.is_empty() { - no_suggestion_details + // We don't have any recommended spelling corrections + alloc.concat(vec![ + alloc.reflow("Is there an "), + alloc.keyword("import"), + alloc.reflow(" or "), + alloc.keyword("exposing"), + alloc.reflow(" missing up-top"), + ]) } else { alloc.stack(vec![ - yes_suggestion_details, + alloc.reflow("Is there an import missing? Perhaps there is a typo. Did you mean one of these?"), alloc .vcat(suggestions.into_iter().map(|v| alloc.string(v.to_string()))) .indent(4), @@ -1543,6 +1591,6 @@ fn module_not_found<'b>( alloc.reflow("` module is not imported:"), ]), alloc.region(lines.convert_region(region)), - to_details(default_no, default_yes), + details, ]) } diff --git a/reporting/src/error/type.rs b/reporting/src/error/type.rs index a9c1251647..8f10a978fb 100644 --- a/reporting/src/error/type.rs +++ b/reporting/src/error/type.rs @@ -1100,7 +1100,6 @@ fn format_category<'b>( ]), alloc.text(" produces:"), ), - List => ( alloc.concat(vec![this_is, alloc.text(" a list")]), alloc.text(" of type:"), @@ -1128,17 +1127,18 @@ fn format_category<'b>( ]), alloc.text(" which was of type:"), ), - + Character => ( + alloc.concat(vec![this_is, alloc.text(" a character")]), + alloc.text(" of type:"), + ), Lambda => ( alloc.concat(vec![this_is, alloc.text(" an anonymous function")]), alloc.text(" of type:"), ), - ClosureSize => ( alloc.concat(vec![this_is, alloc.text(" the closure size of a function")]), alloc.text(" of type:"), ), - TagApply { tag_name: TagName::Global(name), args_count: 0, @@ -1472,6 +1472,7 @@ fn add_pattern_category<'b>( Num => alloc.reflow(" numbers:"), Int => alloc.reflow(" integers:"), Float => alloc.reflow(" floats:"), + Character => alloc.reflow(" characters:"), }; alloc.concat(vec![i_am_trying_to_match, rest]) diff --git a/reporting/tests/test_reporting.rs b/reporting/tests/test_reporting.rs index 356a123373..c16690ec0d 100644 --- a/reporting/tests/test_reporting.rs +++ b/reporting/tests/test_reporting.rs @@ -8274,4 +8274,35 @@ I need all branches in an `if` to have the same type! ), ) } + + #[test] + fn unimported_modules_reported() { + report_problem_as( + indoc!( + r#" + main : Task.Task {} [] + main = "whatever man you don't even know my type" + main + "# + ), + indoc!( + r#" + ── MODULE NOT IMPORTED ───────────────────────────────────────────────────────── + + The `Task` module is not imported: + + 1│ main : Task.Task {} [] + ^^^^^^^^^^^^^^^ + + Is there an import missing? Perhaps there is a typo. Did you mean one + of these? + + Test + List + Num + Set + "# + ), + ) + } } diff --git a/roc_std/Cargo.toml b/roc_std/Cargo.toml index d005f846f5..7565655d4c 100644 --- a/roc_std/Cargo.toml +++ b/roc_std/Cargo.toml @@ -13,4 +13,8 @@ indoc = "1.0.3" pretty_assertions = "1.0.0" quickcheck = "1.0.3" quickcheck_macros = "1.0.0" -libc = "0.2" +libc = "0.2.106" + +[features] +default = ["platform"] +platform = [] diff --git a/roc_std/src/lib.rs b/roc_std/src/lib.rs index addf97fa22..d40457eac4 100644 --- a/roc_std/src/lib.rs +++ b/roc_std/src/lib.rs @@ -15,6 +15,7 @@ pub use roc_list::RocList; pub use roc_str::RocStr; // A list of C functions that are being imported +#[cfg(feature = "platform")] extern "C" { pub fn roc_alloc(size: usize, alignment: u32) -> *mut c_void; pub fn roc_realloc( @@ -26,6 +27,30 @@ extern "C" { pub fn roc_dealloc(ptr: *mut c_void, alignment: u32); } +/// # Safety +/// This is only marked unsafe to typecheck without warnings in the rest of the code here. +#[cfg(not(feature = "platform"))] +pub unsafe extern "C" fn roc_alloc(_size: usize, _alignment: u32) -> *mut c_void { + unimplemented!("It is not valid to call roc alloc from within the compiler. Please use the \"platform\" feature if this is a platform.") +} +/// # Safety +/// This is only marked unsafe to typecheck without warnings in the rest of the code here. +#[cfg(not(feature = "platform"))] +pub unsafe extern "C" fn roc_realloc( + _ptr: *mut c_void, + _new_size: usize, + _old_size: usize, + _alignment: u32, +) -> *mut c_void { + unimplemented!("It is not valid to call roc realloc from within the compiler. Please use the \"platform\" feature if this is a platform.") +} +/// # Safety +/// This is only marked unsafe to typecheck without warnings in the rest of the code here. +#[cfg(not(feature = "platform"))] +pub unsafe extern "C" fn roc_dealloc(_ptr: *mut c_void, _alignment: u32) { + unimplemented!("It is not valid to call roc dealloc from within the compiler. Please use the \"platform\" feature if this is a platform.") +} + #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum RocOrder {