1use std::borrow::Cow;
2use std::cmp::Ordering;
3use std::fmt;
4use std::hash::{Hash, Hasher};
5use std::marker::PhantomData;
6use std::ops::{Deref, DerefMut};
7
8use deser_core::de::{Deserialize, OwnedSink, Sink, SinkHandle};
9use deser_core::ser::{
10 Boxed, Chunk, Describe, SerializeHandle, StructEmitter, Variant, VariantKind, VariantRepr,
11};
12use deser_core::{Atom, Error, ErrorKind, Serialize, State, Text};
13
14use crate::Names;
15
16pub struct Mixed<T, W = KeepWhitespace>(pub Vec<T>, PhantomData<fn() -> W>);
127
128pub trait Whitespace: sealed::Sealed + 'static {
132 #[doc(hidden)]
133 const KEEP: bool;
134}
135
136#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
138pub struct KeepWhitespace;
139
140#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
146pub struct SkipWhitespace;
147
148impl Whitespace for KeepWhitespace {
149 const KEEP: bool = true;
150}
151
152impl Whitespace for SkipWhitespace {
153 const KEEP: bool = false;
154}
155
156mod sealed {
157 pub trait Sealed {}
158 impl Sealed for super::KeepWhitespace {}
159 impl Sealed for super::SkipWhitespace {}
160}
161
162impl<T, W> Mixed<T, W> {
163 pub const fn new() -> Mixed<T, W> {
165 Mixed(Vec::new(), PhantomData)
166 }
167
168 pub fn into_inner(self) -> Vec<T> {
170 self.0
171 }
172}
173
174impl<T: fmt::Debug, W> fmt::Debug for Mixed<T, W> {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 f.debug_tuple("Mixed").field(&self.0).finish()
177 }
178}
179
180impl<T: Clone, W> Clone for Mixed<T, W> {
181 fn clone(&self) -> Mixed<T, W> {
182 Mixed(self.0.clone(), PhantomData)
183 }
184}
185
186impl<T: PartialEq, W> PartialEq for Mixed<T, W> {
187 fn eq(&self, other: &Mixed<T, W>) -> bool {
188 self.0 == other.0
189 }
190}
191
192impl<T: Eq, W> Eq for Mixed<T, W> {}
193
194impl<T: PartialOrd, W> PartialOrd for Mixed<T, W> {
195 fn partial_cmp(&self, other: &Mixed<T, W>) -> Option<Ordering> {
196 self.0.partial_cmp(&other.0)
197 }
198}
199
200impl<T: Ord, W> Ord for Mixed<T, W> {
201 fn cmp(&self, other: &Mixed<T, W>) -> Ordering {
202 self.0.cmp(&other.0)
203 }
204}
205
206impl<T: Hash, W> Hash for Mixed<T, W> {
207 fn hash<H: Hasher>(&self, state: &mut H) {
208 self.0.hash(state)
209 }
210}
211
212impl<T, W> Default for Mixed<T, W> {
213 fn default() -> Mixed<T, W> {
214 Mixed::new()
215 }
216}
217
218impl<T, W> Deref for Mixed<T, W> {
219 type Target = Vec<T>;
220
221 fn deref(&self) -> &Vec<T> {
222 &self.0
223 }
224}
225
226impl<T, W> DerefMut for Mixed<T, W> {
227 fn deref_mut(&mut self) -> &mut Vec<T> {
228 &mut self.0
229 }
230}
231
232impl<T, W> From<Vec<T>> for Mixed<T, W> {
233 fn from(values: Vec<T>) -> Mixed<T, W> {
234 Mixed(values, PhantomData)
235 }
236}
237
238impl<T, W> FromIterator<T> for Mixed<T, W> {
239 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Mixed<T, W> {
240 Mixed(iter.into_iter().collect(), PhantomData)
241 }
242}
243
244impl<T, W> IntoIterator for Mixed<T, W> {
245 type Item = T;
246 type IntoIter = std::vec::IntoIter<T>;
247
248 fn into_iter(self) -> Self::IntoIter {
249 self.0.into_iter()
250 }
251}
252
253impl<'a, T, W> IntoIterator for &'a Mixed<T, W> {
254 type Item = &'a T;
255 type IntoIter = std::slice::Iter<'a, T>;
256
257 fn into_iter(self) -> Self::IntoIter {
258 self.0.iter()
259 }
260}
261
262#[derive(Debug, Default)]
269pub(crate) struct WhitespaceDepths(pub(crate) Vec<usize>);
270
271impl WhitespaceDepths {
272 pub(crate) fn applies(state: &State) -> bool {
274 state
275 .get::<WhitespaceDepths>()
276 .and_then(|keep| keep.0.last())
277 .is_some_and(|&depth| depth == state.depth())
278 }
279
280 pub(crate) fn prune(state: &mut State) {
286 let depth = state.depth();
287 if state.get::<WhitespaceDepths>().is_some() {
288 state
289 .get_mut::<WhitespaceDepths>()
290 .0
291 .retain(|&keep| keep <= depth);
292 }
293 }
294}
295
296impl<'de, T: Deserialize<'de>, W: Whitespace> Deserialize<'de> for Mixed<T, W> {
297 fn deserialize_into<'out>(
298 out: &'out mut Option<Self>,
299 state: &mut State,
300 ) -> SinkHandle<'out, 'de> {
301 SinkHandle::arena(
302 MixedSink {
303 out,
304 values: Vec::new(),
305 key: None,
306 pending: None,
307 depth: None,
308 },
309 state,
310 )
311 }
312
313 fn initial_value() -> Option<Self> {
315 Some(Mixed::new())
316 }
317}
318
319struct MixedSink<'a, 'de, T, W> {
320 out: &'a mut Option<Mixed<T, W>>,
321 values: Vec<T>,
322 key: Option<String>,
323 pending: Option<OwnedSink<'de, T>>,
325 depth: Option<usize>,
327}
328
329impl<'de, T: Deserialize<'de>, W: Whitespace> MixedSink<'_, 'de, T, W> {
330 fn keep_whitespace(&mut self, depth: usize, state: &mut State) {
332 if W::KEEP && self.depth.is_none() {
333 self.depth = Some(depth);
334 state.get_mut::<WhitespaceDepths>().0.push(depth);
335 }
336 }
337
338 fn is_content(text: &str) -> bool {
340 if W::KEEP {
341 !text.is_empty()
342 } else {
343 !text.trim().is_empty()
344 }
345 }
346
347 fn begin(&mut self, key: &str, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
349 self.end(state)?;
350 let pending = self.pending.insert(OwnedSink::deserialize(state));
351 let sink = pending.borrow_mut();
352 sink.map(state)?;
353 let mut key_sink = sink.next_key(state)?;
354 key_sink.atom(Atom::Lexical(Text::borrowed(key)), state)?;
355 key_sink.finish(state)?;
356 drop(key_sink);
357 sink.next_value(state)
358 }
359
360 fn end(&mut self, state: &mut State) -> Result<(), Error> {
364 if let Some(mut pending) = self.pending.take() {
365 pending.borrow_mut().finish(state)?;
366 self.values.extend(pending.take());
367 }
368 Ok(())
369 }
370}
371
372impl<'de, T: Deserialize<'de>, W: Whitespace> Sink<'de> for MixedSink<'_, 'de, T, W> {
373 fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
376 match atom {
377 Atom::Null => Ok(()),
378 Atom::Str(ref text) | Atom::Lexical(ref text) if !Self::is_content(text) => Ok(()),
379 Atom::Str(_) | Atom::Lexical(_) => {
380 let mut sink = self.begin(text_key(state), state)?;
381 sink.atom(atom, state)?;
382 sink.finish(state)
383 }
384 atom => self.unexpected_atom(atom, state),
385 }
386 }
387
388 fn borrowed_atom(&mut self, atom: Atom<'de>, state: &mut State) -> Result<(), Error> {
389 match atom {
390 Atom::Str(ref text) | Atom::Lexical(ref text) if Self::is_content(text) => {
391 let mut sink = self.begin(text_key(state), state)?;
392 sink.borrowed_atom(atom, state)?;
393 sink.finish(state)
394 }
395 atom => self.atom(atom, state),
396 }
397 }
398
399 fn map(&mut self, state: &mut State) -> Result<(), Error> {
400 self.keep_whitespace(state.depth() + 1, state);
402 Ok(())
403 }
404
405 fn next_key(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
406 self.end(state)?;
407 Ok(String::deserialize_into(&mut self.key, state))
408 }
409
410 fn next_value(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
411 let key = self.key.take().unwrap_or_default();
412 Ok(self
413 .value_for_key(&key, state)?
414 .unwrap_or_else(SinkHandle::null))
415 }
416
417 fn value_for_key(
419 &mut self,
420 key: &str,
421 state: &mut State,
422 ) -> Result<Option<SinkHandle<'_, 'de>>, Error> {
423 let prefix = names(state).attribute_prefix;
424 if !prefix.is_empty() && key.starts_with(prefix) {
425 return Ok(None);
426 }
427 self.keep_whitespace(state.depth(), state);
429 self.begin(key, state).map(Some)
430 }
431
432 fn finish(&mut self, state: &mut State) -> Result<(), Error> {
433 self.end(state)?;
434 if let Some(depth) = self.depth.take() {
435 let keep = &mut state.get_mut::<WhitespaceDepths>().0;
436 if keep.last() == Some(&depth) {
437 keep.pop();
438 }
439 }
440 *self.out = Some(Mixed(std::mem::take(&mut self.values), PhantomData));
441 Ok(())
442 }
443
444 fn recover(&mut self, err: Error, state: &mut State) -> Result<(), Error> {
445 self.key = None;
446 match self.pending {
447 Some(ref mut pending) => pending.borrow_mut().recover(err, state),
448 None => Err(err),
449 }
450 }
451
452 fn expecting(&self) -> Cow<'_, str> {
453 Cow::Borrowed("mixed content")
454 }
455}
456
457fn names(state: &State) -> &Names {
458 const DEFAULT: Names = Names::new();
459 state.get::<Names>().unwrap_or(&DEFAULT)
460}
461
462fn text_key(state: &State) -> &'static str {
463 names(state).text_key
464}
465
466#[derive(Debug, Default, Clone)]
472pub(crate) struct KeepsWhitespace(pub(crate) bool);
473
474impl<T: Serialize, W: Whitespace> Serialize for Mixed<T, W> {
475 fn serialize(&self, state: &mut State) -> Result<Chunk<'_>, Error> {
476 if W::KEEP {
477 state.event_mut::<KeepsWhitespace>().0 = true;
478 }
479 Ok(Chunk::structure(
480 MixedEmitter {
481 values: self.0.iter(),
482 current: None,
483 },
484 state,
485 ))
486 }
487}
488
489enum Entries<'a> {
491 Struct(Boxed<dyn StructEmitter + 'a>),
492 Unit(Option<Cow<'a, str>>),
494}
495
496struct MixedEmitter<'a, T> {
497 values: std::slice::Iter<'a, T>,
498 current: Option<(&'a T, Entries<'a>)>,
499}
500
501impl<'a, T: Serialize> StructEmitter for MixedEmitter<'a, T> {
502 fn next(
503 &mut self,
504 state: &mut State,
505 ) -> Result<Option<(Cow<'_, str>, SerializeHandle<'_>)>, Error> {
506 loop {
507 if let Some((_, ref mut entries)) = self.current {
508 let entry = match entries {
509 Entries::Struct(emitter) => emitter.next(state)?,
510 Entries::Unit(name) => name.take().map(|name| (name, SerializeHandle::to(&""))),
511 };
512 let entry = unsafe {
518 std::mem::transmute::<
519 Option<(Cow<'_, str>, SerializeHandle<'_>)>,
520 Option<(Cow<'a, str>, SerializeHandle<'a>)>,
521 >(entry)
522 };
523 if let Some(entry) = entry {
524 return Ok(Some(entry));
525 }
526 let (value, entries) = self.current.take().unwrap();
527 drop(entries);
528 value.finish(state)?;
529 }
530 let Some(value) = self.values.next() else {
531 return Ok(None);
532 };
533 let entries = match value.serialize(state)? {
534 Chunk::Struct(emitter) => Entries::Struct(emitter),
535 Chunk::Atom(Atom::Str(name) | Atom::Lexical(name)) if is_unit_variant(value) => {
536 Entries::Unit(Some(name.into_cow()))
537 }
538 Chunk::Atom(Atom::Null) => Entries::Unit(None),
539 _ => {
540 return Err(Error::new(
541 ErrorKind::UnsupportedType,
542 "the values of mixed content must be structs or externally tagged enums",
543 ));
544 }
545 };
546 self.current = Some((value, entries));
547 }
548 }
549}
550
551fn is_unit_variant(value: &dyn Serialize) -> bool {
553 struct Check(bool);
554
555 impl Describe for Check {
556 fn variant(&mut self, variant: &Variant<'_>) {
557 self.0 = variant.kind == VariantKind::Unit && variant.repr == VariantRepr::External;
558 }
559 }
560
561 let mut check = Check(false);
562 value.describe(&mut check);
563 check.0
564}