Skip to content

Commit

Permalink
feat: Add IntoOwned trait (#597)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdy1 committed Oct 9, 2023
1 parent 7ff93ca commit 6a5ad49
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 10 deletions.
61 changes: 53 additions & 8 deletions derive/src/into_owned.rs
Expand Up @@ -2,15 +2,15 @@ use proc_macro::{self, TokenStream};
use proc_macro2::Span;
use quote::quote;
use syn::{
parse_macro_input, Data, DataEnum, DeriveInput, Field, Fields, GenericArgument, Ident, Member, PathArguments,
Type,
parse_macro_input, parse_quote, Data, DataEnum, DeriveInput, Field, Fields, GenericArgument, Ident, Member,
PathArguments, Type,
};

pub(crate) fn derive_into_owned(input: TokenStream) -> TokenStream {
let DeriveInput {
ident: self_name,
data,
generics,
mut generics,
..
} = parse_macro_input!(input);

Expand Down Expand Up @@ -105,16 +105,61 @@ pub(crate) fn derive_into_owned(input: TokenStream) -> TokenStream {
}
};

let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let orig_generics = generics.clone();

let into_owned = if generics.lifetimes().next().is_none() {
panic!("can't derive IntoOwned on a type without any lifetimes")
// Add generic bounds for all type parameters.
let mut type_param_names = vec![];

for ty in generics.type_params() {
type_param_names.push(ty.ident.clone());
}

for type_param in type_param_names {
generics.make_where_clause().predicates.push_value(parse_quote! {
#type_param: 'static + for<'aa> crate::traits::IntoOwned<'aa>
})
}

let has_lifetime = generics
.params
.first()
.map_or(false, |v| matches!(v, syn::GenericParam::Lifetime(..)));

// Prepend `'any` to generics
let any = syn::GenericParam::Lifetime(syn::LifetimeDef {
attrs: Default::default(),
lifetime: syn::Lifetime {
apostrophe: Span::call_site(),
ident: Ident::new("any", Span::call_site()),
},
colon_token: None,
bounds: Default::default(),
});
generics.params.insert(0, any.clone());

let (impl_generics, _, where_clause) = generics.split_for_impl();
let (_, ty_generics, _) = orig_generics.split_for_impl();

let into_owned = if !has_lifetime {
quote! {
impl #impl_generics crate::traits::IntoOwned<'any> for #self_name #ty_generics #where_clause {
type Owned = Self;

#[inline]
fn into_owned(self) -> Self {
self
}
}
}
} else {
let params = generics.type_params();
quote! {
impl #impl_generics #self_name #ty_generics #where_clause {
impl #impl_generics crate::traits::IntoOwned<'any> for #self_name #ty_generics #where_clause {
type Owned = #self_name<'any, #(#params),*>;
/// Consumes the value and returns an owned clone.
pub fn into_owned<'x>(self) -> #self_name<'x, #(#params),*> {
fn into_owned(self) -> Self::Owned {
use crate::traits::IntoOwned;

#res
}
}
Expand Down
1 change: 1 addition & 0 deletions node/src/transformer.rs
Expand Up @@ -3,6 +3,7 @@ use std::{
ops::{Index, IndexMut},
};

use lightningcss::traits::IntoOwned;
use lightningcss::{
media_query::MediaFeatureValue,
properties::{
Expand Down
2 changes: 2 additions & 0 deletions src/error.rs
Expand Up @@ -2,6 +2,8 @@

use crate::properties::custom::Token;
use crate::rules::Location;
#[cfg(feature = "into_owned")]
use crate::traits::IntoOwned;
use crate::values::string::CowArcStr;
use cssparser::{BasicParseErrorKind, ParseError, ParseErrorKind};
use parcel_selectors::parser::SelectorParseErrorKind;
Expand Down
4 changes: 3 additions & 1 deletion src/media_query.rs
@@ -1,5 +1,4 @@
//! Media queries.

use crate::error::{ErrorWithLocation, MinifyError, MinifyErrorKind, ParserError, PrinterError};
use crate::macros::enum_property;
use crate::parser::starts_with_ignore_ascii_case;
Expand All @@ -11,6 +10,8 @@ use crate::rules::custom_media::CustomMediaRule;
use crate::rules::Location;
use crate::stylesheet::ParserOptions;
use crate::targets::{should_compile, Targets};
#[cfg(feature = "into_owned")]
use crate::traits::IntoOwned;
use crate::traits::{Parse, ToCss};
use crate::values::ident::{DashedIdent, Ident};
use crate::values::number::{CSSInteger, CSSNumber};
Expand Down Expand Up @@ -1257,6 +1258,7 @@ macro_rules! define_query_features {
pub(crate) use define_query_features;

define_query_features! {
#[cfg_attr(feature = "into_owned", derive(lightningcss_derive::IntoOwned))]
/// A media query feature identifier.
pub enum MediaFeatureId {
/// The [width](https://w3c.github.io/csswg-drafts/mediaqueries-5/#width) media feature.
Expand Down
1 change: 1 addition & 0 deletions src/properties/custom.rs
Expand Up @@ -180,6 +180,7 @@ impl<'i> UnparsedProperty<'i> {
) -> Result<super::Property<'x>, ()> {
use super::Property;
use crate::stylesheet::PrinterOptions;
use crate::traits::IntoOwned;

// Substitute variables in the token list.
self.value.substitute_variables(vars);
Expand Down
2 changes: 2 additions & 0 deletions src/properties/mod.rs
Expand Up @@ -128,6 +128,8 @@ use crate::parser::ParserOptions;
use crate::prefixes::Feature;
use crate::printer::{Printer, PrinterOptions};
use crate::targets::Targets;
#[cfg(feature = "into_owned")]
use crate::traits::IntoOwned;
use crate::traits::{Parse, ParseWithOptions, Shorthand, ToCss};
use crate::values::number::{CSSInteger, CSSNumber};
use crate::values::string::CowArcStr;
Expand Down
1 change: 1 addition & 0 deletions src/rules/container.rs
Expand Up @@ -74,6 +74,7 @@ pub type ContainerSizeFeature<'i> = QueryFeature<'i, ContainerSizeFeatureId>;

define_query_features! {
/// A container query size feature identifier.
#[cfg_attr(feature = "into_owned", derive(lightningcss_derive::IntoOwned))]
pub enum ContainerSizeFeatureId {
/// The [width](https://w3c.github.io/csswg-drafts/css-contain-3/#width) size container feature.
"width": Width = Length,
Expand Down
32 changes: 32 additions & 0 deletions src/traits.rs
Expand Up @@ -10,6 +10,38 @@ use crate::targets::{Browsers, Targets};
use crate::vendor_prefix::VendorPrefix;
use cssparser::*;

/// A trait for things that can be cloned with a new lifetime.
///
/// `'any` lifeitme means the output should have `'static` lifetime.
#[cfg(feature = "into_owned")]
pub trait IntoOwned<'any> {
/// A variant of `Self` with a new lifetime.
type Owned: 'any;

/// Make lifetime of `self` `'static`.
fn into_owned(self) -> Self::Owned;
}

#[cfg(feature = "into_owned")]
macro_rules! impl_into_owned {
($t: ty) => {
impl<'a> IntoOwned<'a> for $t {
type Owned = Self;

#[inline]
fn into_owned(self) -> Self {
self
}
}
};
($($t:ty),*) => {
$(impl_into_owned!($t);)*
};
}

#[cfg(feature = "into_owned")]
impl_into_owned!(bool, f32, f64, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);

/// Trait for things that can be parsed from CSS syntax.
pub trait Parse<'i>: Sized {
/// Parse a value of this type using an existing parser.
Expand Down
7 changes: 6 additions & 1 deletion src/values/string.rs
Expand Up @@ -129,9 +129,14 @@ impl<'a> CowArcStr<'a> {
}
}
}
}

#[cfg(feature = "into_owned")]
impl<'any> crate::traits::IntoOwned<'any> for CowArcStr<'_> {
type Owned = CowArcStr<'any>;

/// Consumes the value and returns an owned clone.
pub fn into_owned<'x>(self) -> CowArcStr<'x> {
fn into_owned(self) -> Self::Owned {
if self.borrowed_len_or_max != usize::MAX {
CowArcStr::from(self.as_ref().to_owned())
} else {
Expand Down

0 comments on commit 6a5ad49

Please sign in to comment.