Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require generic associated types #75

Merged
merged 4 commits into from
Sep 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ jobs:
fail-fast: false
matrix:
os: [macos-latest, windows-latest]
toolchain: [stable]
# TODO: use stable once GATs reach stable
toolchain: [beta]
include:
- os: ubuntu-latest
toolchain: "1.58.0"
toolchain: "1.65.0"
- os: ubuntu-latest
toolchain: beta

Expand Down
3 changes: 0 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ harfbuzz = ["harfbuzz_rs"]
# Enable Markdown parsing
markdown = ["pulldown-cmark"]

# Use Generic Associated Types (experimental)
gat = []

# Serialization is optionally supported for some types:
# serde

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ Non-pure-Rust alternatives include [font-kit](https://crates.io/crates/font-kit)
and [piet](https://crates.io/crates/piet) among others.


MSRV
---

The Minium Supported Rust Version is 1.65.0.


Contributing
--------

Expand Down
3 changes: 3 additions & 0 deletions src/fonts/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ impl<'a> FaceStore<'a> {

#[derive(Default)]
struct FaceList {
// Safety: unsafe code depends on entries never moving (hence the otherwise
// redundant use of Box). See e.g. FontLibrary::get_face().
#[allow(clippy::vec_box)]
faces: Vec<Box<FaceStore<'static>>>,
// These are vec-maps. Why? Because length should be short.
path_hash: Vec<(u64, FaceId)>,
Expand Down
2 changes: 1 addition & 1 deletion src/fonts/selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ enum State {
fn to_uppercase<'a>(c: Cow<'a, str>) -> Cow<'a, str> {
match c {
Cow::Borrowed(b) if !b.chars().any(|c| c.is_lowercase()) => Cow::Borrowed(b),
c => Cow::Owned(c.to_owned().to_uppercase()),
c => Cow::Owned(c.to_uppercase()),
}
}

Expand Down
36 changes: 3 additions & 33 deletions src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,7 @@ pub use markdown::{Error as MarkdownError, Markdown};
///
/// Any `F: FormattableText` automatically support [`FormattableTextDyn`].
/// Implement either this or [`FormattableTextDyn`], not both.
///
/// This trait can only be written as intended using Generic Associated Types
/// (`gat`, unstable nightly feature), thus `font_tokens` has a different
/// signature with/without feature `gat` and the associated type
/// `FontTokenIter` is only present with feature `gat`.
pub trait FormattableText: std::fmt::Debug {
#[cfg_attr(doc_cfg, doc(cfg(feature = "gat")))]
#[cfg(feature = "gat")]
// TODO: rename → Iter
type FontTokenIter<'a>: Iterator<Item = FontToken>
where
Self: 'a;
Expand All @@ -53,20 +45,8 @@ pub trait FormattableText: std::fmt::Debug {
/// The `dpem` parameter is font size as in [`crate::Environment`].
///
/// For plain text this iterator will be empty.
#[cfg(feature = "gat")]
fn font_tokens<'a>(&'a self, dpem: f32) -> Self::FontTokenIter<'a>;

/// Construct an iterator over formatting items
///
/// It is expected that [`FontToken::start`] of yielded items is strictly
/// increasing; if not, formatting may not be applied correctly.
///
/// The `dpem` parameter is font size as in [`crate::Environment`].
///
/// For plain text this iterator will be empty.
#[cfg(not(feature = "gat"))]
fn font_tokens(&self, dpem: f32) -> OwningVecIter<FontToken>;

/// Get the sequence of effect tokens
///
/// This method has some limitations: (1) it may only return a reference to
Expand Down Expand Up @@ -117,7 +97,6 @@ pub trait FormattableTextDyn: std::fmt::Debug {
fn effect_tokens(&self) -> &[Effect<()>];
}

// #[cfg(feature = "gat")]
impl<F: FormattableText + Clone + 'static> FormattableTextDyn for F {
fn clone_boxed(&self) -> Box<dyn FormattableTextDyn> {
Box::new(self.clone())
Expand All @@ -132,14 +111,7 @@ impl<F: FormattableText + Clone + 'static> FormattableTextDyn for F {

fn font_tokens(&self, dpem: f32) -> OwningVecIter<FontToken> {
let iter = FormattableText::font_tokens(self, dpem);
#[cfg(feature = "gat")]
{
OwningVecIter::new(iter.collect())
}
#[cfg(not(feature = "gat"))]
{
iter
}
OwningVecIter::new(iter.collect())
}

fn effect_tokens(&self) -> &[Effect<()>] {
Expand All @@ -148,11 +120,9 @@ impl<F: FormattableText + Clone + 'static> FormattableTextDyn for F {
}

impl<'t> FormattableText for &'t dyn FormattableTextDyn {
#[cfg(feature = "gat")]
type FontTokenIter<'a>
type FontTokenIter<'a> = OwningVecIter<FontToken>
where
Self: 'a,
= OwningVecIter<FontToken>;
Self: 'a,;

#[inline]
fn str_len(&self) -> usize {
Expand Down
10 changes: 0 additions & 10 deletions src/format/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
use super::{EditableText, FontToken, FormattableText};
use crate::conv::to_u32;
use crate::fonts::{self, FontId, FontSelector, Style, Weight};
#[cfg(not(feature = "gat"))]
use crate::OwningVecIter;
use crate::{Effect, EffectFlags};
use pulldown_cmark::{Event, HeadingLevel, Tag};
use std::fmt::Write;
Expand Down Expand Up @@ -108,25 +106,17 @@ impl<'a> ExactSizeIterator for FontTokenIter<'a> {}
impl<'a> FusedIterator for FontTokenIter<'a> {}

impl FormattableText for Markdown {
#[cfg(feature = "gat")]
type FontTokenIter<'a> = FontTokenIter<'a>;

#[inline]
fn as_str(&self) -> &str {
&self.text
}

#[cfg(feature = "gat")]
#[inline]
fn font_tokens<'a>(&'a self, dpem: f32) -> Self::FontTokenIter<'a> {
FontTokenIter::new(&self.fmt, dpem)
}
#[cfg(not(feature = "gat"))]
#[inline]
fn font_tokens(&self, dpem: f32) -> OwningVecIter<FontToken> {
let iter = FontTokenIter::new(&self.fmt, dpem);
OwningVecIter::new(iter.collect())
}

fn effect_tokens(&self) -> &[Effect<()>] {
&self.effects
Expand Down
19 changes: 2 additions & 17 deletions src/format/plain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,50 +7,35 @@

use super::{EditableText, FontToken, FormattableText};
use crate::Effect;
#[cfg(not(feature = "gat"))]
use crate::OwningVecIter;

impl<'t> FormattableText for &'t str {
#[cfg(feature = "gat")]
type FontTokenIter<'a>
type FontTokenIter<'a> = std::iter::Empty<FontToken>
where
Self: 'a,
= std::iter::Empty<FontToken>;
Self: 'a;

fn as_str(&self) -> &str {
self
}

#[cfg(feature = "gat")]
fn font_tokens<'a>(&'a self, _: f32) -> Self::FontTokenIter<'a> {
std::iter::empty()
}
#[cfg(not(feature = "gat"))]
fn font_tokens(&self, _: f32) -> OwningVecIter<FontToken> {
OwningVecIter::new(Vec::new())
}

fn effect_tokens(&self) -> &[Effect<()>] {
&[]
}
}

impl FormattableText for String {
#[cfg(feature = "gat")]
type FontTokenIter<'a> = std::iter::Empty<FontToken>;

fn as_str(&self) -> &str {
self
}

#[cfg(feature = "gat")]
fn font_tokens<'a>(&'a self, _: f32) -> Self::FontTokenIter<'a> {
std::iter::empty()
}
#[cfg(not(feature = "gat"))]
fn font_tokens(&self, _: f32) -> OwningVecIter<FontToken> {
OwningVecIter::new(Vec::new())
}

fn effect_tokens(&self) -> &[Effect<()>] {
&[]
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
//! [`format`]: mod@format

#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(feature = "gat", feature(generic_associated_types))]
#![allow(clippy::len_zero)]
#![allow(clippy::type_complexity)]
#![allow(clippy::unit_arg)]
Expand Down