Skip to content

Commit

Permalink
Merge pull request #200 from Kijewski/pr-ref
Browse files Browse the repository at this point in the history
Unify trait impl for reference wrapper types
  • Loading branch information
GuillaumeGomez authored Oct 23, 2024
2 parents 6a02bed + f48d265 commit 1e319fd
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 80 deletions.
42 changes: 20 additions & 22 deletions rinja/src/filters/builtin.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::cell::Cell;
use std::convert::Infallible;
use std::fmt::{self, Write};
use std::ops::Deref;
use std::pin::Pin;

use super::escape::{FastWritable, HtmlSafeOutput};
use crate::{Error, Result};
Expand Down Expand Up @@ -829,32 +831,28 @@ pub trait PluralizeCount {
}

const _: () = {
// implement PluralizeCount for a list of reference wrapper types to PluralizeCount
macro_rules! impl_pluralize_count_for_ref {
($T:ident => $($ty:ty)*) => { $(
impl<T: PluralizeCount + ?Sized> PluralizeCount for $ty {
type Error = <T as PluralizeCount>::Error;
crate::impl_for_ref! {
impl PluralizeCount for T {
type Error = T::Error;

#[inline]
fn is_singular(&self) -> Result<bool, Self::Error> {
<T as PluralizeCount>::is_singular(self)
}
#[inline]
fn is_singular(&self) -> Result<bool, Self::Error> {
<T>::is_singular(self)
}
)* };
}
}

impl_pluralize_count_for_ref! {
T =>
&T
Box<T>
std::cell::Ref<'_, T>
std::cell::RefMut<'_, T>
std::pin::Pin<&T>
std::rc::Rc<T>
std::sync::Arc<T>
std::sync::MutexGuard<'_, T>
std::sync::RwLockReadGuard<'_, T>
std::sync::RwLockWriteGuard<'_, T>
impl<T> PluralizeCount for Pin<T>
where
T: Deref,
<T as Deref>::Target: PluralizeCount,
{
type Error = <<T as Deref>::Target as PluralizeCount>::Error;

#[inline]
fn is_singular(&self) -> Result<bool, Self::Error> {
self.as_ref().get_ref().is_singular()
}
}

/// implement `PluralizeCount` for unsigned integer types
Expand Down
38 changes: 17 additions & 21 deletions rinja/src/filters/escape.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::convert::Infallible;
use std::fmt::{self, Formatter, Write};
use std::ops::Deref;
use std::pin::Pin;
use std::{borrow, str};

/// Marks a string (or other `Display` type) as safe
Expand Down Expand Up @@ -502,30 +504,24 @@ pub trait FastWritable {
}

const _: () = {
// implement FastWritable for a list of reference wrapper types to FastWritable+?Sized
macro_rules! impl_for_ref {
($T:ident => $($ty:ty)*) => { $(
impl<$T: FastWritable + ?Sized> FastWritable for $ty {
#[inline]
fn write_into<W: fmt::Write + ?Sized>(&self, dest: &mut W) -> fmt::Result {
<$T>::write_into(self, dest)
}
crate::impl_for_ref! {
impl FastWritable for T {
#[inline]
fn write_into<W: fmt::Write + ?Sized>(&self, dest: &mut W) -> fmt::Result {
<T>::write_into(self, dest)
}
)* };
}
}

impl_for_ref! {
T =>
&T
Box<T>
std::cell::Ref<'_, T>
std::cell::RefMut<'_, T>
std::pin::Pin<&T>
std::rc::Rc<T>
std::sync::Arc<T>
std::sync::MutexGuard<'_, T>
std::sync::RwLockReadGuard<'_, T>
std::sync::RwLockWriteGuard<'_, T>
impl<T> FastWritable for Pin<T>
where
T: Deref,
<T as Deref>::Target: FastWritable,
{
#[inline]
fn write_into<W: fmt::Write + ?Sized>(&self, dest: &mut W) -> fmt::Result {
self.as_ref().get_ref().write_into(dest)
}
}

impl<T: FastWritable + ToOwned> FastWritable for borrow::Cow<'_, T> {
Expand Down
38 changes: 17 additions & 21 deletions rinja/src/filters/json.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::convert::Infallible;
use std::ops::Deref;
use std::pin::Pin;
use std::{fmt, io, str};

use serde::Serialize;
Expand Down Expand Up @@ -144,30 +146,24 @@ impl<T: AsIndent + ToOwned + ?Sized> AsIndent for std::borrow::Cow<'_, T> {
}
}

// implement AsIdent for a list of reference wrapper types to AsIdent
macro_rules! impl_as_ident_for_ref {
($T:ident => $($ty:ty)*) => { $(
impl<T: AsIndent + ?Sized> AsIndent for $ty {
#[inline]
fn as_indent(&self) -> &str {
<T>::as_indent(self)
}
crate::impl_for_ref! {
impl AsIndent for T {
#[inline]
fn as_indent(&self) -> &str {
<T>::as_indent(self)
}
)* };
}
}

impl_as_ident_for_ref! {
T =>
&T
Box<T>
std::cell::Ref<'_, T>
std::cell::RefMut<'_, T>
std::pin::Pin<&T>
std::rc::Rc<T>
std::sync::Arc<T>
std::sync::MutexGuard<'_, T>
std::sync::RwLockReadGuard<'_, T>
std::sync::RwLockWriteGuard<'_, T>
impl<T> AsIndent for Pin<T>
where
T: Deref,
<T as Deref>::Target: AsIndent,
{
#[inline]
fn as_indent(&self) -> &str {
self.as_ref().get_ref().as_indent()
}
}

impl<S: Serialize> FastWritable for ToJson<S> {
Expand Down
75 changes: 60 additions & 15 deletions rinja/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::cell::Cell;
use std::fmt;
use std::iter::{Enumerate, Peekable};
use std::ops::Deref;
use std::pin::Pin;

// The re-exports are used in the generated code for macro hygiene. Even if the paths `::core` or
// `::std` are shadowed, the generated code will still be able to access the crates.
Expand Down Expand Up @@ -91,23 +93,15 @@ where
}
}

pub fn get_primitive_value<T: PrimitiveType>(value: &T) -> T::Value {
#[inline]
pub fn get_primitive_value<T: PrimitiveType>(value: T) -> T::Value {
value.get()
}

pub trait PrimitiveType: Copy {
type Value: Copy;

fn get(self) -> Self::Value;
}
pub trait PrimitiveType {
type Value;

impl<T: PrimitiveType> PrimitiveType for &T {
type Value = T::Value;

#[inline]
fn get(self) -> Self::Value {
T::get(*self)
}
fn get(&self) -> Self::Value;
}

macro_rules! primitive_type {
Expand All @@ -116,8 +110,8 @@ macro_rules! primitive_type {
type Value = $ty;

#[inline]
fn get(self) -> Self::Value {
self
fn get(&self) -> Self::Value {
*self
}
}
)*};
Expand All @@ -130,6 +124,57 @@ primitive_type! {
u8, u16, u32, u64, u128, usize,
}

crate::impl_for_ref! {
impl PrimitiveType for T {
type Value = T::Value;

#[inline]
fn get(&self) -> Self::Value {
<T>::get(self)
}
}
}

impl<T> PrimitiveType for Pin<T>
where
T: Deref,
<T as Deref>::Target: PrimitiveType,
{
type Value = <<T as Deref>::Target as PrimitiveType>::Value;

#[inline]
fn get(&self) -> Self::Value {
self.as_ref().get_ref().get()
}
}

/// Implement [`PrimitiveType`] for [`Cell<T>`]
///
/// ```
/// # use std::cell::Cell;
/// # use std::rc::Rc;
/// # use std::pin::Pin;
/// # use rinja::Template;
/// #[derive(Template)]
/// #[template(ext = "txt", source = "{{ value as u16 }}")]
/// struct Test<'a> {
/// value: &'a Pin<Rc<Cell<i16>>>
/// }
///
/// assert_eq!(
/// Test { value: &Rc::pin(Cell::new(-1)) }.to_string(),
/// "65535",
/// );
/// ```
impl<T: PrimitiveType + Copy> PrimitiveType for Cell<T> {
type Value = T::Value;

#[inline]
fn get(&self) -> Self::Value {
self.get().get()
}
}

/// An empty element, so nothing will be written.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Empty;
Expand Down
25 changes: 25 additions & 0 deletions rinja/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,31 @@ impl fmt::Display for dyn DynTemplate {
}
}

/// Implement the trait `$Trait` for a list of reference (wrapper) types to `$T: $Trait + ?Sized`
macro_rules! impl_for_ref {
(impl $Trait:ident for $T:ident $body:tt) => {
crate::impl_for_ref! {
impl<$T> $Trait for [
&T
&mut T
Box<T>
std::cell::Ref<'_, T>
std::cell::RefMut<'_, T>
std::rc::Rc<T>
std::sync::Arc<T>
std::sync::MutexGuard<'_, T>
std::sync::RwLockReadGuard<'_, T>
std::sync::RwLockWriteGuard<'_, T>
] $body
}
};
(impl<$T:ident> $Trait:ident for [$($ty:ty)*] $body:tt) => {
$(impl<$T: $Trait + ?Sized> $Trait for $ty $body)*
}
}

pub(crate) use impl_for_ref;

#[cfg(test)]
mod tests {
use std::fmt;
Expand Down
2 changes: 1 addition & 1 deletion testing/tests/ui/pluralize.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ error[E0277]: the trait bound `str: PluralizeCount` is not satisfied
|
= help: the following other types implement trait `PluralizeCount`:
&T
&mut T
Arc<T>
Box<T>
MutexGuard<'_, T>
NonZero<i128>
NonZero<i16>
NonZero<i32>
NonZero<i64>
and $N others
= note: required for `&str` to implement `PluralizeCount`
= note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)

0 comments on commit 1e319fd

Please sign in to comment.