Merge #140: Bootstrappable builds

ef20b782301bae2fdfb842dfd89a749e60cb449e guix: make the builds actually reproducible (Antoine Poinsot)
72a332d2caf6c139d20855203d107fe3b185ba7d guix: fix the dependencies listing for the GUI container (Antoine Poinsot)
4a38040acf12dd457ac5f29a24f4b3800114255c guix: documentation (Antoine Poinsot)
37a28dbf7d5a22426d1844ef792d04e604e5b91b guix: use a lighter environment for building the daemon (Antoine Poinsot)
ae0b24f97494a7a859578ab6191187c4405a225f guix: allow to limit the number of cores dedicated to the build (Antoine Poinsot)
940c28d072c449295f6e1225446b829bea2d3053 guix: use patchelf to strip interpreter and RPATH (Antoine Poinsot)
3906a1b5bc5e7f57925981b4dd009fc6b13de7c1 guix: reproducible builds of the GUI (Antoine Poinsot)
8dda896e4b2c4baa69b5e1b839bfaf47b9b36320 guix: Linux reproducible builds of the daemon (Antoine Poinsot)

Pull request description:

  This introduces reproducible and bootstrappable builds of our softwares by using [Guix](https://guix.gnu.org/). This is heavily inspired by the work on Guix [that was done in the Bitcoin Core project](https://github.com/bitcoin/bitcoin/tree/master/contrib/guix). For an intro to reproducible builds with Guix see [this post](https://guix.gnu.org/blog/2020/reproducible-computations-with-guix/).

  For details, see the documentation introduced in this PR. Apologies for the poor commit history.

ACKs for top commit:
  darosior:
    ACK ef20b782301bae2fdfb842dfd89a749e60cb449e

Tree-SHA512: 58800170a8fd0822129f1fefa23c8a8cb68e8758a56b3ea9933b41cff1eff7691ed735a28f156395b76c18447044f2ba5a3f4cd519696667b6df90e27e20d3f6
This commit is contained in:
Antoine Poinsot 2022-12-13 14:52:39 +01:00
commit f9359869f7
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304
6 changed files with 835 additions and 3 deletions

View File

@ -56,6 +56,3 @@ libc = "0.2"
# Used for PSBTs
base64 = "0.13"
[patch.crates-io]

176
contrib/guix/README.md Normal file
View File

@ -0,0 +1,176 @@
## Bootstrappable Liana builds
This repository contains the scripts to perform [reproducible](https://reproducible-builds.org/) and
[bootstrappable](https://bootstrappable.org/) builds of Liana using [Guix](https://guix.gnu.org/), a
functional package manager.
For a short high-level introduction to the purpose of bootstrappable builds, see [this
talk](https://www.youtube.com/watch?v=I2iShmUTEl8) by Carl Dong in the context of the Bitcoin Core
project.
For now, only `x86_64` Linux binaries are supported. We aim to extend bootstrappable builds to more
targets in the future.
### Installation
See the very [detailed document about GUIX installation in the Bitcoin Core
project](https://github.com/bitcoin/bitcoin/blob/master/contrib/guix/INSTALL.md). Almost all of it
is directly applicable to Liana as well.
### Usage
First of all, you need to decide on the amount of trust in the building process. Of course this
decision needs to fall within a broader threat model, but it is still interesting to consider.
*(Note: this section was taken from the Bitcoin Core documentation and initially written by Carl
Dong.)*
#### Choosing your security model
No matter how you installed Guix, you need to decide on your security model for
building packages with Guix.
Guix allows us to achieve better binary security by using our CPU time to build
everything from scratch. However, it doesn't sacrifice user choice in pursuit of
this: users can decide whether or not to use **substitutes** (pre-built
packages).
##### Option 1: Building with substitutes
###### Step 1: Authorize the signing keys
Depending on the installation procedure you followed, you may have already
authorized the Guix build farm key. In particular, the official shell installer
script asks you if you want the key installed, and the debian distribution
package authorized the key during installation.
You can check the current list of authorized keys at `/etc/guix/acl`.
At the time of writing, a `/etc/guix/acl` with just the Guix build farm key
authorized looks something like:
```lisp
(acl
(entry
(public-key
(ecc
(curve Ed25519)
(q #8D156F295D24B0D9A86FA5741A840FF2D24F60F7B6C4134814AD55625971B394#)
)
)
(tag
(guix import)
)
)
)
```
If you've determined that the official Guix build farm key hasn't been
authorized, and you would like to authorize it, run the following as root:
```
guix archive --authorize < /var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub
```
If
`/var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub`
doesn't exist, try:
```sh
guix archive --authorize < <PREFIX>/share/guix/ci.guix.gnu.org.pub
```
Where `<PREFIX>` is likely:
- `/usr` if you installed from a distribution package
- `/usr/local` if you installed Guix from source and didn't supply any
prefix-modifying flags to Guix's `./configure`
For dongcarl's substitute server at https://guix.carldong.io, run as root:
```sh
wget -qO- 'https://guix.carldong.io/signing-key.pub' | guix archive --authorize
```
To remove previously authorized keys, simply edit `/etc/guix/acl` and remove the
`(entry (public-key ...))` entry.
###### Step 2: Specify the substitute servers
Once its key is authorized, the official Guix build farm at
https://ci.guix.gnu.org is automatically used unless the `--no-substitutes` flag
is supplied. This default list of substitute servers is overridable both on a
`guix-daemon` level and when you invoke `guix` commands. See examples below for
the various ways of adding dongcarl's substitute server after having [authorized
his signing key](#step-1-authorize-the-signing-keys).
Change the **default list** of substitute servers by starting `guix-daemon` with
the `--substitute-urls` option (you will likely need to edit your init script):
```sh
guix-daemon <cmd> --substitute-urls='https://guix.carldong.io https://ci.guix.gnu.org'
```
Override the default list of substitute servers by passing the
`--substitute-urls` option for invocations of `guix` commands:
```sh
guix <cmd> --substitute-urls='https://guix.carldong.io https://ci.guix.gnu.org'
```
For scripts under `./contrib/guix`, set the `SUBSTITUTE_URLS` environment
variable:
```sh
export SUBSTITUTE_URLS='https://guix.carldong.io https://ci.guix.gnu.org'
```
##### Option 2: Disabling substitutes on an ad-hoc basis
If you prefer not to use any substitutes, make sure to supply `--no-substitutes`
like in the following snippet. The first build will take a while, but the
resulting packages will be cached for future builds.
For direct invocations of `guix`:
```sh
guix <cmd> --no-substitutes
```
The build script doesn't yet allow you to provide this via an environment variable, you'd
have to modify it yourself (or contribute a patch :p).
##### Option 3: Disabling substitutes by default
`guix-daemon` accepts a `--no-substitutes` flag, which will make sure that,
unless otherwise overridden by a command line invocation, no substitutes will be
used.
If you start `guix-daemon` using an init script, you can edit said script to
supply this flag.
#### Building Liana
For both the daemon (`lianad`) and the GUI (`liana-gui`), the [`guix-build.sh`](./guix-build.sh)
script will vendor the dependencies of the project (as pinned in the `Cargo.lock`) and start a [GUIX
container](https://guix.gnu.org/manual/devel/en/html_node/Invoking-guix-shell.html) that will run
the `build.sh` script that will take care of building the dependencies and the project using `cargo`.
To start a build, simply run the `guix-build.sh` script from the root of the repository:
```
$ ./contrib/guix/guix-build.sh
```
The script shouldn't contain any bash-ism, so it should work with other shells as well.
#### Customization
Environment variables are available to configure the build.
`BUILD_ROOT` allows you to specify the root folder that will contain the vendored dependencies'
source, the build cache as well as the resulting binaries (in `$BUILD_ROOT/out`).
`JOBS` allows you to specify the number of cores to dedicate to the build both for bootstrapping the
toolchain with GUIX and building the project using `cargo`.

45
contrib/guix/build.sh Executable file
View File

@ -0,0 +1,45 @@
# ==========================================================================
# The script ran within the GUIX container to build the Liana daemon or GUI.
# ==========================================================================
set -ex
# Instruct cargo to use our vendored sources
mkdir -p ~/.cargo
cat <<EOF >~/.cargo/config.toml
[source.vendored_sources]
directory = "/vendor"
[source.crates-io]
replace-with = "vendored_sources"
[source."https://github.com/darosior/rust-miniscript"]
git = "https://github.com/darosior/rust-miniscript"
branch = "multipath_descriptors_on_8.0"
replace-with = "vendored_sources"
[source."https://github.com/revault/liana"]
git = "https://github.com/revault/liana"
branch = "master"
replace-with = "vendored_sources"
EOF
# We need to set RUSTC_BOOTSTRAP=1 as a workaround to be able to use unstable
# features in the GUI dependencies
RUSTC_BOOTSTRAP=1 cargo -vvv \
--color always \
--frozen \
--offline \
rustc \
--jobs "$JOBS" \
--release \
--target-dir "/out"
# Assume 64bits. Even bitcoind doesn't ship 32bits binaries for x86.
# FIXME: is there a cleaner way than using patchelf for this?
patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 "/out/release/$BINARY_NAME"
# FIXME: Find a way to use GUIX_LD_WRAPPER_DISABLE_RPATH=yes instead
patchelf --remove-rpath "/out/release/$BINARY_NAME"
set +ex

140
contrib/guix/guix-build.sh Executable file
View File

@ -0,0 +1,140 @@
#!/usr/bin/env sh
set -ex
# How many cores to allocate to Guix building.
JOBS="${JOBS:-$(nproc)}"
# The binary to check the hash of downloaded archives.
SHASUM_BIN="${SHASUM_BIN:-sha256sum}"
# We do everything in a single directory. That's the root of it, configurable
# through the environment.
BUILD_ROOT="${BUILD_ROOT:-$(mktemp -d)}"
# Various folders we expose to the container. The vendor directory will contain
# the sources of all our dependencies. Because we restrict network access from
# within the container, this is pulled beforehand.
# The out directory will contain the resulting binaries. It's wired to the --target-dir
# for a cargo build.
VENDOR_DIR="$BUILD_ROOT/vendor"
OUT_DIR="${OUT_DIR:-"$BUILD_ROOT/out"}"
BIN_DIR="${BIN_DIR:-"$BUILD_ROOT/bin"}"
# Create the directory if it doesn't exist already
maybe_create_dir() {
if ! [ -d "$@" ]; then
mkdir -p "$@"
fi
}
maybe_create_dir "$BIN_DIR"
# That's what Guix comes with.
RUST_VERSION="1.60.0"
CARGO_BIN="$BIN_DIR/cargo"
# First off get the cargo binary to run on the host to vendor dependencies.
# We assume the host is a 64bit Linux system.
if ! [ -f "$CARGO_BIN" ]; then
ARCHIVE_PATH="$BIN_DIR/rust-for-cargo.tar.gz"
curl -o "$ARCHIVE_PATH" "https://static.rust-lang.org/dist/rust-$RUST_VERSION-x86_64-unknown-linux-gnu.tar.gz"
echo "b8a4c3959367d053825e31f90a5eb86418eb0d80cacda52bfa80b078e18150d5 $ARCHIVE_PATH" | $SHASUM_BIN -c
# Path of the cargo binary within the archive
CARGO_BIN_PATH="rust-$RUST_VERSION-x86_64-unknown-linux-gnu/cargo/bin/cargo"
( cd $BIN_DIR && tar -xzf $ARCHIVE_PATH $CARGO_BIN_PATH && mv $CARGO_BIN_PATH $CARGO_BIN )
fi
# Execute "$@" in a pinned, possibly older version of Guix, for reproducibility
# across time.
time_machine() {
guix time-machine --url=https://git.savannah.gnu.org/git/guix.git \
--commit=059d38dc3f8b087f4a42df586daeb05761ee18d7 \
--cores="$JOBS" \
--keep-failed \
--fallback \
-- "$@"
}
# Build both the daemon (at the root of the repository) and the GUI (in gui/)
for project_folder in "" "gui"; do
PROJECT_ROOT="$PWD/$project_folder"
PROJECT_VENDOR_DIR="$VENDOR_DIR/$project_folder"
PROJECT_OUT_DIR="$OUT_DIR/$project_folder"
PROJECT_PATCHES_ROOT="$PWD/contrib/guix/patches/$project_folder"
project_needs_patches() {
test $(ls -A1q "$PROJECT_PATCHES_ROOT" |grep patch)
}
maybe_create_dir "$PROJECT_OUT_DIR"
# Pull the sources of our dependencies before building them in the container.
if ! [ -d "$PROJECT_VENDOR_DIR" ]; then
# Download the dependencies
( cd "$project_folder" && $CARGO_BIN vendor "$PROJECT_VENDOR_DIR" )
# Patch some dependencies sources if needed for this project
if project_needs_patches; then
(
cd "$PROJECT_VENDOR_DIR"
for patch_file in $(ls "$PROJECT_PATCHES_ROOT"); do
patch -p1 < "$PROJECT_PATCHES_ROOT/$patch_file"
done
)
# Some of the checksums will be incorrect. Instead of cherry-picking remove them
# altogether, since they aren't useful anyways (see comment below).
for dep in $(ls "$PROJECT_VENDOR_DIR"); do
echo "{\"files\":{}}" > "$PROJECT_VENDOR_DIR/$dep/.cargo-checksum.json"
done
fi
fi
cp "$PROJECT_ROOT/Cargo.lock" "$BUILD_ROOT/Cargo.lock"
if project_needs_patches; then
# Remove the checksums from the Cargo.lock. In the container `cargo rustc` would compare
# them against the .cargo-checksum.json to make sure they weren't tampered with since they
# where vendored. But we just removed the checksums from the .cargo-checksum.json.
# There is little point in checking integrity between the above vendor step and now anyways.
# What matters is checking integrity after downloading the crates from the internet and
# `cargo vendor` does that already.
sed -i '/checksum/d' "$BUILD_ROOT/Cargo.lock"
fi
# FIXME: find a cleaner way to get the binary name, or get rid of patchelf entirely
# Note: we also rely on it in manifest.scm
if [ "$project_folder" = "" ]; then
BINARY_NAME="lianad"
elif [ "$project_folder" = "gui" ]; then
BINARY_NAME="liana-gui"
else
echo "Can't determine binary name"
exit 1
fi
# Bootstrap a reproducible environment as specified by the manifest in an isolated
# container, and build the project.
# NOTE: it looks like "--rebuild-cache" is necessary for the BINARY_NAME variable to
# be taken into account when building the container (otherwise the GUI container could
# miss some dependencies).
BINARY_NAME="$BINARY_NAME" time_machine shell --no-cwd \
--expose="$PROJECT_ROOT/src=/liana/src" \
--expose="$PWD/gui/static=/liana/static" \
--expose="$PROJECT_ROOT/Cargo.toml=/liana/Cargo.toml" \
--expose="$BUILD_ROOT/Cargo.lock=/liana/Cargo.lock" \
--expose="$PWD/contrib/guix/build.sh=/liana/build.sh" \
--expose="$PROJECT_VENDOR_DIR=/vendor" \
--share="$PROJECT_OUT_DIR=/out" \
--cores="$JOBS" \
--container \
--pure \
--fallback \
--rebuild-cache \
-m $PWD/contrib/guix/manifest.scm \
-- env CC=gcc VENDOR_DIR="$PROJECT_VENDOR_DIR" TARGET_DIR="$PROJECT_OUT_DIR" BINARY_NAME="$BINARY_NAME" JOBS="$JOBS" \
/bin/sh -c "cd /liana && ./build.sh"
done
set +ex
echo "Build successful. Output available at $OUT_DIR"

15
contrib/guix/manifest.scm Normal file
View File

@ -0,0 +1,15 @@
(specifications->manifest
(append
(list "rust"
"rust:cargo"
"coreutils"
"patchelf"
"gcc-toolchain@10.3.0")
;; Additional dependencies for building the GUI
(let ((binary_name (getenv "BINARY_NAME")))
(if
(string=? binary_name "liana-gui")
(list "pkg-config"
"eudev"
"fontconfig")
'()))))

View File

@ -0,0 +1,459 @@
commit f71bc71bf6724a1c5e2a3246dd8bd0a90fcf0e15
Author: Antoine Poinsot <darosior@protonmail.com>
Date: Thu Dec 1 15:38:32 2022 +0100
Do not use, or special-case them, unstable features as of 1.60.0
This is in order to make the GUI MSRV effectively 1.60.0.
Default derivation on enums is removed.
Usage of bool_to_option is removed.
Generic associated types is unfortunately special cased as enabled. This
forces use to set RUSTC_BOOTSTRAP=1 in the Guix container...
diff --git a/iced_glow/src/lib.rs b/iced_glow/src/lib.rs
index e3690a69..b5b9cc38 100644
--- a/iced_glow/src/lib.rs
+++ b/iced_glow/src/lib.rs
@@ -20,6 +20,7 @@
#![forbid(rust_2018_idioms)]
#![allow(clippy::inherent_to_string, clippy::type_complexity)]
#![cfg_attr(docsrs, feature(doc_cfg))]
+#![feature(generic_associated_types)]
pub use glow;
diff --git a/iced_graphics/src/lib.rs b/iced_graphics/src/lib.rs
index d39dd90c..876b478f 100644
--- a/iced_graphics/src/lib.rs
+++ b/iced_graphics/src/lib.rs
@@ -21,6 +21,7 @@
#![forbid(rust_2018_idioms)]
#![allow(clippy::inherent_to_string, clippy::type_complexity)]
#![cfg_attr(docsrs, feature(doc_cfg))]
+#![feature(generic_associated_types)]
mod antialiasing;
mod error;
mod primitive;
diff --git a/iced_native/src/program/state.rs b/iced_native/src/program/state.rs
index 8ae1cacb..25a3028b 100644
--- a/iced_native/src/program/state.rs
+++ b/iced_native/src/program/state.rs
@@ -120,7 +120,11 @@ where
.iter()
.zip(event_statuses)
.filter_map(|(event, status)| {
- matches!(status, event::Status::Ignored).then_some(event)
+ if matches!(status, event::Status::Ignored) {
+ Some(event)
+ } else {
+ None
+ }
})
.cloned()
.collect();
diff --git a/iced_style/src/theme.rs b/iced_style/src/theme.rs
index d7ebb827..224a04fc 100644
--- a/iced_style/src/theme.rs
+++ b/iced_style/src/theme.rs
@@ -25,10 +25,9 @@ use iced_core::{Background, Color, Vector};
use std::rc::Rc;
/// A built-in theme.
-#[derive(Debug, Clone, PartialEq, Default)]
+#[derive(Debug, Clone, PartialEq)]
pub enum Theme {
/// The built-in light variant.
- #[default]
Light,
/// The built-in dark variant.
Dark,
@@ -61,6 +60,12 @@ impl Theme {
}
}
+impl Default for Theme {
+ fn default() -> Self {
+ Self::Light
+ }
+}
+
/// A [`Theme`] with a customized [`Palette`].
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Custom {
@@ -79,15 +84,19 @@ impl Custom {
}
/// The style of an application.
-#[derive(Default)]
pub enum Application {
/// The default style.
- #[default]
Default,
/// A custom style.
Custom(Box<dyn application::StyleSheet<Style = Theme>>),
}
+impl Default for Application {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
impl application::StyleSheet for Theme {
type Style = Application;
@@ -119,10 +128,11 @@ impl From<fn(&Theme) -> application::Appearance> for Application {
}
/// The style of a button.
-#[derive(Default)]
+/*
+ * Button
+ */
pub enum Button {
/// The primary style.
- #[default]
Primary,
/// The secondary style.
Secondary,
@@ -138,6 +148,12 @@ pub enum Button {
Custom(Box<dyn button::StyleSheet<Style = Theme>>),
}
+impl Default for Button {
+ fn default() -> Self {
+ Self::Primary
+ }
+}
+
impl button::StyleSheet for Theme {
type Style = Button;
@@ -227,10 +243,11 @@ impl button::StyleSheet for Theme {
}
/// The style of a checkbox.
-#[derive(Default)]
+/*
+ * Checkbox
+ */
pub enum Checkbox {
/// The primary style.
- #[default]
Primary,
/// The secondary style.
Secondary,
@@ -242,6 +259,12 @@ pub enum Checkbox {
Custom(Box<dyn checkbox::StyleSheet<Style = Theme>>),
}
+impl Default for Checkbox {
+ fn default() -> Self {
+ Self::Primary
+ }
+}
+
impl checkbox::StyleSheet for Theme {
type Style = Checkbox;
@@ -339,10 +362,11 @@ fn checkbox_appearance(
}
/// The style of a container.
-#[derive(Default)]
+/*
+ * Container
+ */
pub enum Container {
/// No style.
- #[default]
Transparent,
/// A simple box.
Box,
@@ -350,6 +374,12 @@ pub enum Container {
Custom(Box<dyn container::StyleSheet<Style = Theme>>),
}
+impl Default for Container {
+ fn default() -> Self {
+ Self::Transparent
+ }
+}
+
impl From<fn(&Theme) -> container::Appearance> for Container {
fn from(f: fn(&Theme) -> container::Appearance) -> Self {
Self::Custom(Box::new(f))
@@ -387,15 +417,19 @@ impl container::StyleSheet for fn(&Theme) -> container::Appearance {
}
/// The style of a slider.
-#[derive(Default)]
pub enum Slider {
/// The default style.
- #[default]
Default,
/// A custom style.
Custom(Box<dyn slider::StyleSheet<Style = Theme>>),
}
+impl Default for Slider {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
impl slider::StyleSheet for Theme {
type Style = Slider;
@@ -468,15 +502,20 @@ impl slider::StyleSheet for Theme {
}
/// The style of a menu.
-#[derive(Clone, Default)]
+#[derive(Clone)]
pub enum Menu {
/// The default style.
- #[default]
Default,
/// A custom style.
Custom(Rc<dyn menu::StyleSheet<Style = Theme>>),
}
+impl Default for Menu {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
impl menu::StyleSheet for Theme {
type Style = Menu;
@@ -510,10 +549,9 @@ impl From<PickList> for Menu {
}
/// The style of a pick list.
-#[derive(Clone, Default)]
+#[derive(Clone)]
pub enum PickList {
/// The default style.
- #[default]
Default,
/// A custom style.
Custom(
@@ -522,6 +560,12 @@ pub enum PickList {
),
}
+impl Default for PickList {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
impl pick_list::StyleSheet for Theme {
type Style = PickList;
@@ -565,15 +609,19 @@ impl pick_list::StyleSheet for Theme {
}
/// The style of a radio button.
-#[derive(Default)]
pub enum Radio {
/// The default style.
- #[default]
Default,
/// A custom style.
Custom(Box<dyn radio::StyleSheet<Style = Theme>>),
}
+impl Default for Radio {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
impl radio::StyleSheet for Theme {
type Style = Radio;
@@ -620,15 +668,19 @@ impl radio::StyleSheet for Theme {
}
/// The style of a toggler.
-#[derive(Default)]
pub enum Toggler {
/// The default style.
- #[default]
Default,
/// A custom style.
Custom(Box<dyn toggler::StyleSheet<Style = Theme>>),
}
+impl Default for Toggler {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
impl toggler::StyleSheet for Theme {
type Style = Toggler;
@@ -687,15 +739,19 @@ impl toggler::StyleSheet for Theme {
}
/// The style of a pane grid.
-#[derive(Default)]
pub enum PaneGrid {
/// The default style.
- #[default]
Default,
/// A custom style.
Custom(Box<dyn pane_grid::StyleSheet<Style = Theme>>),
}
+impl Default for PaneGrid {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
impl pane_grid::StyleSheet for Theme {
type Style = PaneGrid;
@@ -729,10 +785,11 @@ impl pane_grid::StyleSheet for Theme {
}
/// The style of a progress bar.
-#[derive(Default)]
+/*
+ * Progress Bar
+ */
pub enum ProgressBar {
/// The primary style.
- #[default]
Primary,
/// The success style.
Success,
@@ -742,6 +799,12 @@ pub enum ProgressBar {
Custom(Box<dyn progress_bar::StyleSheet<Style = Theme>>),
}
+impl Default for ProgressBar {
+ fn default() -> Self {
+ Self::Primary
+ }
+}
+
impl From<fn(&Theme) -> progress_bar::Appearance> for ProgressBar {
fn from(f: fn(&Theme) -> progress_bar::Appearance) -> Self {
Self::Custom(Box::new(f))
@@ -782,15 +845,22 @@ impl progress_bar::StyleSheet for fn(&Theme) -> progress_bar::Appearance {
}
/// The style of a rule.
-#[derive(Default)]
+/*
+ * Rule
+ */
pub enum Rule {
/// The default style.
- #[default]
Default,
/// A custom style.
Custom(Box<dyn rule::StyleSheet<Style = Theme>>),
}
+impl Default for Rule {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
impl From<fn(&Theme) -> rule::Appearance> for Rule {
fn from(f: fn(&Theme) -> rule::Appearance) -> Self {
Self::Custom(Box::new(f))
@@ -824,15 +894,19 @@ impl rule::StyleSheet for fn(&Theme) -> rule::Appearance {
}
/// The style of a scrollable.
-#[derive(Default)]
pub enum Scrollable {
/// The default style.
- #[default]
Default,
/// A custom style.
Custom(Box<dyn scrollable::StyleSheet<Style = Theme>>),
}
+impl Default for Scrollable {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
impl scrollable::StyleSheet for Theme {
type Style = Scrollable;
@@ -889,15 +963,23 @@ impl scrollable::StyleSheet for Theme {
}
/// The style of text.
-#[derive(Clone, Copy, Default)]
+/*
+ * Text
+ */
+#[derive(Clone, Copy)]
pub enum Text {
/// The default style.
- #[default]
Default,
/// Colored text.
Color(Color),
}
+impl Default for Text {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
impl From<Color> for Text {
fn from(color: Color) -> Self {
Text::Color(color)
@@ -916,15 +998,19 @@ impl text::StyleSheet for Theme {
}
/// The style of a text input.
-#[derive(Default)]
pub enum TextInput {
/// The default style.
- #[default]
Default,
/// A custom style.
Custom(Box<dyn text_input::StyleSheet<Style = Theme>>),
}
+impl Default for TextInput {
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
impl text_input::StyleSheet for Theme {
type Style = TextInput;
diff --git a/iced_wgpu/src/lib.rs b/iced_wgpu/src/lib.rs
index dcb699e8..5b3cda57 100644
--- a/iced_wgpu/src/lib.rs
+++ b/iced_wgpu/src/lib.rs
@@ -37,6 +37,7 @@
#![forbid(rust_2018_idioms)]
#![allow(clippy::inherent_to_string, clippy::type_complexity)]
#![cfg_attr(docsrs, feature(doc_cfg))]
+#![feature(generic_associated_types)]
pub mod settings;
pub mod triangle;