|
1 | | -use std::ops::{Index, IndexMut}; |
| 1 | +use std::{ |
| 2 | + marker::PhantomData, |
| 3 | + ops::{Index, IndexMut}, |
| 4 | +}; |
2 | 5 |
|
3 | 6 | use lightningcss::{ |
4 | 7 | media_query::MediaFeatureValue, |
@@ -487,7 +490,7 @@ impl<'i> Visitor<'i, AtRule<'i>> for JsVisitor { |
487 | 490 | .as_ref() |
488 | 491 | .and_then(|v| self.env.get_reference_value_unchecked::<JsFunction>(v).ok()) |
489 | 492 | { |
490 | | - map(&mut selectors.0, |value| { |
| 493 | + map::<_, _, _, true>(&mut selectors.0, |value| { |
491 | 494 | let js_value = self.env.to_js_value(value)?; |
492 | 495 | let res = visit.call(None, &[js_value])?; |
493 | 496 | self.env.from_js_value(res).map(serde_detach::detach) |
@@ -664,7 +667,7 @@ fn visit_list< |
664 | 667 | }) |
665 | 668 | } |
666 | 669 |
|
667 | | -fn map<V, L: List<V>, F: FnMut(&mut V) -> napi::Result<Option<ValueOrVec<V>>>>( |
| 670 | +fn map<V, L: List<V>, F: FnMut(&mut V) -> napi::Result<Option<ValueOrVec<V, IS_VEC>>>, const IS_VEC: bool>( |
668 | 671 | list: &mut L, |
669 | 672 | mut f: F, |
670 | 673 | ) -> napi::Result<()> { |
@@ -694,13 +697,70 @@ fn map<V, L: List<V>, F: FnMut(&mut V) -> napi::Result<Option<ValueOrVec<V>>>>( |
694 | 697 | Ok(()) |
695 | 698 | } |
696 | 699 |
|
697 | | -#[derive(serde::Serialize, serde::Deserialize)] |
| 700 | +#[derive(serde::Serialize)] |
698 | 701 | #[serde(untagged)] |
699 | | -enum ValueOrVec<V> { |
| 702 | +enum ValueOrVec<V, const IS_VEC: bool = false> { |
700 | 703 | Value(V), |
701 | 704 | Vec(Vec<V>), |
702 | 705 | } |
703 | 706 |
|
| 707 | +// Manually implemented deserialize for better error messages. |
| 708 | +// https://github.com/serde-rs/serde/issues/773 |
| 709 | +impl<'de, V: serde::Deserialize<'de>, const IS_VEC: bool> serde::Deserialize<'de> for ValueOrVec<V, IS_VEC> { |
| 710 | + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| 711 | + where |
| 712 | + D: serde::Deserializer<'de>, |
| 713 | + { |
| 714 | + use serde::Deserializer; |
| 715 | + let content = serde::__private::de::Content::deserialize(deserializer)?; |
| 716 | + let de: serde::__private::de::ContentRefDeserializer<D::Error> = |
| 717 | + serde::__private::de::ContentRefDeserializer::new(&content); |
| 718 | + |
| 719 | + // Try to deserialize as a sequence first. |
| 720 | + let mut was_seq = false; |
| 721 | + let res = de.deserialize_seq(SeqVisitor { |
| 722 | + was_seq: &mut was_seq, |
| 723 | + phantom: PhantomData, |
| 724 | + }); |
| 725 | + |
| 726 | + if was_seq { |
| 727 | + // Allow fallback if we know the value is also a list (e.g. selector). |
| 728 | + if res.is_ok() || !IS_VEC { |
| 729 | + return res.map(ValueOrVec::Vec); |
| 730 | + } |
| 731 | + } |
| 732 | + |
| 733 | + // If it wasn't a sequence, try a value. |
| 734 | + let de = serde::__private::de::ContentRefDeserializer::new(&content); |
| 735 | + return V::deserialize(de).map(ValueOrVec::Value); |
| 736 | + |
| 737 | + struct SeqVisitor<'a, V> { |
| 738 | + was_seq: &'a mut bool, |
| 739 | + phantom: PhantomData<V>, |
| 740 | + } |
| 741 | + |
| 742 | + impl<'a, 'de, V: serde::Deserialize<'de>> serde::de::Visitor<'de> for SeqVisitor<'a, V> { |
| 743 | + type Value = Vec<V>; |
| 744 | + |
| 745 | + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { |
| 746 | + formatter.write_str("a sequence") |
| 747 | + } |
| 748 | + |
| 749 | + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> |
| 750 | + where |
| 751 | + A: serde::de::SeqAccess<'de>, |
| 752 | + { |
| 753 | + *self.was_seq = true; |
| 754 | + let mut vec = Vec::with_capacity(seq.size_hint().unwrap_or(1)); |
| 755 | + while let Some(v) = seq.next_element()? { |
| 756 | + vec.push(v); |
| 757 | + } |
| 758 | + Ok(vec) |
| 759 | + } |
| 760 | + } |
| 761 | + } |
| 762 | +} |
| 763 | + |
704 | 764 | trait List<V>: Index<usize, Output = V> + IndexMut<usize, Output = V> { |
705 | 765 | fn len(&self) -> usize; |
706 | 766 | fn remove(&mut self, i: usize); |
|
0 commit comments