Skip to content

Commit 6a5ad49

Browse files
authored
feat: Add IntoOwned trait (parcel-bundler#597)
1 parent 7ff93ca commit 6a5ad49

File tree

9 files changed

+101
-10
lines changed

9 files changed

+101
-10
lines changed

derive/src/into_owned.rs

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ use proc_macro::{self, TokenStream};
22
use proc_macro2::Span;
33
use quote::quote;
44
use syn::{
5-
parse_macro_input, Data, DataEnum, DeriveInput, Field, Fields, GenericArgument, Ident, Member, PathArguments,
6-
Type,
5+
parse_macro_input, parse_quote, Data, DataEnum, DeriveInput, Field, Fields, GenericArgument, Ident, Member,
6+
PathArguments, Type,
77
};
88

99
pub(crate) fn derive_into_owned(input: TokenStream) -> TokenStream {
1010
let DeriveInput {
1111
ident: self_name,
1212
data,
13-
generics,
13+
mut generics,
1414
..
1515
} = parse_macro_input!(input);
1616

@@ -105,16 +105,61 @@ pub(crate) fn derive_into_owned(input: TokenStream) -> TokenStream {
105105
}
106106
};
107107

108-
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
108+
let orig_generics = generics.clone();
109109

110-
let into_owned = if generics.lifetimes().next().is_none() {
111-
panic!("can't derive IntoOwned on a type without any lifetimes")
110+
// Add generic bounds for all type parameters.
111+
let mut type_param_names = vec![];
112+
113+
for ty in generics.type_params() {
114+
type_param_names.push(ty.ident.clone());
115+
}
116+
117+
for type_param in type_param_names {
118+
generics.make_where_clause().predicates.push_value(parse_quote! {
119+
#type_param: 'static + for<'aa> crate::traits::IntoOwned<'aa>
120+
})
121+
}
122+
123+
let has_lifetime = generics
124+
.params
125+
.first()
126+
.map_or(false, |v| matches!(v, syn::GenericParam::Lifetime(..)));
127+
128+
// Prepend `'any` to generics
129+
let any = syn::GenericParam::Lifetime(syn::LifetimeDef {
130+
attrs: Default::default(),
131+
lifetime: syn::Lifetime {
132+
apostrophe: Span::call_site(),
133+
ident: Ident::new("any", Span::call_site()),
134+
},
135+
colon_token: None,
136+
bounds: Default::default(),
137+
});
138+
generics.params.insert(0, any.clone());
139+
140+
let (impl_generics, _, where_clause) = generics.split_for_impl();
141+
let (_, ty_generics, _) = orig_generics.split_for_impl();
142+
143+
let into_owned = if !has_lifetime {
144+
quote! {
145+
impl #impl_generics crate::traits::IntoOwned<'any> for #self_name #ty_generics #where_clause {
146+
type Owned = Self;
147+
148+
#[inline]
149+
fn into_owned(self) -> Self {
150+
self
151+
}
152+
}
153+
}
112154
} else {
113155
let params = generics.type_params();
114156
quote! {
115-
impl #impl_generics #self_name #ty_generics #where_clause {
157+
impl #impl_generics crate::traits::IntoOwned<'any> for #self_name #ty_generics #where_clause {
158+
type Owned = #self_name<'any, #(#params),*>;
116159
/// Consumes the value and returns an owned clone.
117-
pub fn into_owned<'x>(self) -> #self_name<'x, #(#params),*> {
160+
fn into_owned(self) -> Self::Owned {
161+
use crate::traits::IntoOwned;
162+
118163
#res
119164
}
120165
}

node/src/transformer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::{
33
ops::{Index, IndexMut},
44
};
55

6+
use lightningcss::traits::IntoOwned;
67
use lightningcss::{
78
media_query::MediaFeatureValue,
89
properties::{

src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
use crate::properties::custom::Token;
44
use crate::rules::Location;
5+
#[cfg(feature = "into_owned")]
6+
use crate::traits::IntoOwned;
57
use crate::values::string::CowArcStr;
68
use cssparser::{BasicParseErrorKind, ParseError, ParseErrorKind};
79
use parcel_selectors::parser::SelectorParseErrorKind;

src/media_query.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//! Media queries.
2-
32
use crate::error::{ErrorWithLocation, MinifyError, MinifyErrorKind, ParserError, PrinterError};
43
use crate::macros::enum_property;
54
use crate::parser::starts_with_ignore_ascii_case;
@@ -11,6 +10,8 @@ use crate::rules::custom_media::CustomMediaRule;
1110
use crate::rules::Location;
1211
use crate::stylesheet::ParserOptions;
1312
use crate::targets::{should_compile, Targets};
13+
#[cfg(feature = "into_owned")]
14+
use crate::traits::IntoOwned;
1415
use crate::traits::{Parse, ToCss};
1516
use crate::values::ident::{DashedIdent, Ident};
1617
use crate::values::number::{CSSInteger, CSSNumber};
@@ -1257,6 +1258,7 @@ macro_rules! define_query_features {
12571258
pub(crate) use define_query_features;
12581259

12591260
define_query_features! {
1261+
#[cfg_attr(feature = "into_owned", derive(lightningcss_derive::IntoOwned))]
12601262
/// A media query feature identifier.
12611263
pub enum MediaFeatureId {
12621264
/// The [width](https://w3c.github.io/csswg-drafts/mediaqueries-5/#width) media feature.

src/properties/custom.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ impl<'i> UnparsedProperty<'i> {
180180
) -> Result<super::Property<'x>, ()> {
181181
use super::Property;
182182
use crate::stylesheet::PrinterOptions;
183+
use crate::traits::IntoOwned;
183184

184185
// Substitute variables in the token list.
185186
self.value.substitute_variables(vars);

src/properties/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ use crate::parser::ParserOptions;
128128
use crate::prefixes::Feature;
129129
use crate::printer::{Printer, PrinterOptions};
130130
use crate::targets::Targets;
131+
#[cfg(feature = "into_owned")]
132+
use crate::traits::IntoOwned;
131133
use crate::traits::{Parse, ParseWithOptions, Shorthand, ToCss};
132134
use crate::values::number::{CSSInteger, CSSNumber};
133135
use crate::values::string::CowArcStr;

src/rules/container.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ pub type ContainerSizeFeature<'i> = QueryFeature<'i, ContainerSizeFeatureId>;
7474

7575
define_query_features! {
7676
/// A container query size feature identifier.
77+
#[cfg_attr(feature = "into_owned", derive(lightningcss_derive::IntoOwned))]
7778
pub enum ContainerSizeFeatureId {
7879
/// The [width](https://w3c.github.io/csswg-drafts/css-contain-3/#width) size container feature.
7980
"width": Width = Length,

src/traits.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,38 @@ use crate::targets::{Browsers, Targets};
1010
use crate::vendor_prefix::VendorPrefix;
1111
use cssparser::*;
1212

13+
/// A trait for things that can be cloned with a new lifetime.
14+
///
15+
/// `'any` lifeitme means the output should have `'static` lifetime.
16+
#[cfg(feature = "into_owned")]
17+
pub trait IntoOwned<'any> {
18+
/// A variant of `Self` with a new lifetime.
19+
type Owned: 'any;
20+
21+
/// Make lifetime of `self` `'static`.
22+
fn into_owned(self) -> Self::Owned;
23+
}
24+
25+
#[cfg(feature = "into_owned")]
26+
macro_rules! impl_into_owned {
27+
($t: ty) => {
28+
impl<'a> IntoOwned<'a> for $t {
29+
type Owned = Self;
30+
31+
#[inline]
32+
fn into_owned(self) -> Self {
33+
self
34+
}
35+
}
36+
};
37+
($($t:ty),*) => {
38+
$(impl_into_owned!($t);)*
39+
};
40+
}
41+
42+
#[cfg(feature = "into_owned")]
43+
impl_into_owned!(bool, f32, f64, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
44+
1345
/// Trait for things that can be parsed from CSS syntax.
1446
pub trait Parse<'i>: Sized {
1547
/// Parse a value of this type using an existing parser.

src/values/string.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,14 @@ impl<'a> CowArcStr<'a> {
129129
}
130130
}
131131
}
132+
}
133+
134+
#[cfg(feature = "into_owned")]
135+
impl<'any> crate::traits::IntoOwned<'any> for CowArcStr<'_> {
136+
type Owned = CowArcStr<'any>;
132137

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

0 commit comments

Comments
 (0)