1use std::borrow::Cow;
2use std::collections::HashMap;
3use std::ffi::OsString;
4use std::sync::Arc;
5
6use deser_core::Text;
7use deser_core::de::{
8 self, Deserialize, DeserializeDriver, DeserializeOwned, DuplicateKeys, LexicalRules,
9};
10use deser_core::{Atom, Bytes, ContainerShape, Error, ErrorKind, Event};
11
12use crate::{Case, EnvVar};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct DeserializerConfig {
33 separator: &'static str,
34 case: Case,
35 max_depth: usize,
36 context: deser_core::Context,
37}
38
39impl Default for DeserializerConfig {
40 fn default() -> DeserializerConfig {
41 DeserializerConfig::new()
42 }
43}
44
45impl DeserializerConfig {
46 pub const fn new() -> DeserializerConfig {
48 DeserializerConfig {
49 separator: "__",
50 case: Case::Upper,
51 max_depth: 16,
52 context: deser_core::Context::new(),
53 }
54 }
55
56 pub const fn builder() -> DeserializerConfigBuilder {
58 DeserializerConfigBuilder::new()
59 }
60
61 pub const fn into_builder(self) -> DeserializerConfigBuilder {
63 DeserializerConfigBuilder { value: self }
64 }
65
66 pub fn set_context(&mut self, context: deser_core::Context) {
74 self.context = context;
75 }
76
77 pub fn context(&self) -> &deser_core::Context {
79 &self.context
80 }
81
82 pub const fn set_separator(&mut self, separator: &'static str) {
89 self.separator = separator;
90 }
91
92 pub const fn set_case(&mut self, case: Case) {
96 self.case = case;
97 }
98
99 pub const fn set_max_depth(&mut self, depth: usize) {
104 self.max_depth = depth;
105 }
106
107 pub fn from_env<T: DeserializeOwned>(&self, prefix: &str) -> Result<T, Error> {
111 Deserializer::from_env_with_config(prefix, self.clone()).deserialize()
112 }
113
114 pub fn from_vars<'a, T, I, K, V>(&self, prefix: &str, vars: I) -> Result<T, Error>
118 where
119 T: Deserialize<'a>,
120 I: IntoIterator<Item = (K, V)>,
121 K: Into<Cow<'a, str>>,
122 V: Into<Cow<'a, str>>,
123 {
124 Deserializer::from_vars_with_config(prefix, vars, self.clone()).deserialize()
125 }
126}
127
128#[derive(Debug, Clone)]
132#[must_use]
133pub struct DeserializerConfigBuilder {
134 value: DeserializerConfig,
135}
136
137impl DeserializerConfigBuilder {
138 pub const fn new() -> DeserializerConfigBuilder {
140 DeserializerConfigBuilder {
141 value: DeserializerConfig::new(),
142 }
143 }
144
145 pub const fn separator(mut self, separator: &'static str) -> DeserializerConfigBuilder {
149 self.value.set_separator(separator);
150 self
151 }
152
153 pub const fn case(mut self, case: Case) -> DeserializerConfigBuilder {
157 self.value.set_case(case);
158 self
159 }
160
161 pub const fn max_depth(mut self, depth: usize) -> DeserializerConfigBuilder {
165 self.value.set_max_depth(depth);
166 self
167 }
168
169 pub fn context(mut self, context: deser_core::Context) -> DeserializerConfigBuilder {
173 self.value.set_context(context);
174 self
175 }
176
177 pub const fn build(self) -> DeserializerConfig {
179 let value = unsafe { core::ptr::read(&self.value) };
183 core::mem::forget(self);
184 value
185 }
186}
187
188impl Default for DeserializerConfigBuilder {
189 fn default() -> DeserializerConfigBuilder {
190 DeserializerConfigBuilder::new()
191 }
192}
193
194enum Value<'a> {
196 Text(Cow<'a, str>),
197 Bytes(Vec<u8>),
199}
200
201struct Var<'a> {
203 name: Arc<str>,
205 prefix_len: usize,
207 value: Value<'a>,
208}
209
210pub struct Deserializer<'a> {
237 vars: Vec<Var<'a>>,
238 error: Option<Error>,
240 config: DeserializerConfig,
241}
242
243impl Deserializer<'static> {
244 pub fn from_env(prefix: &str) -> Deserializer<'static> {
246 Deserializer::from_env_with_config(prefix, DeserializerConfig::new())
247 }
248
249 pub fn from_env_with_config(prefix: &str, config: DeserializerConfig) -> Deserializer<'static> {
257 let mut rv = Deserializer {
258 vars: Vec::new(),
259 error: None,
260 config,
261 };
262 for (name, value) in std::env::vars_os() {
263 let name = match name.into_string() {
264 Ok(name) => name,
265 Err(name) => {
266 if strip_prefix(&name.to_string_lossy(), prefix).is_some() {
267 rv.fail(Error::new(
268 ErrorKind::Syntax,
269 format!(
270 "the name of the environment variable {:?} is not valid unicode",
271 name
272 ),
273 ));
274 }
275 continue;
276 }
277 };
278 if strip_prefix(&name, prefix).is_none() {
279 continue;
280 }
281 let value = match value.into_string() {
282 Ok(value) => Value::Text(Cow::Owned(value)),
283 Err(value) => match os_bytes(value) {
284 Some(bytes) => Value::Bytes(bytes),
285 None => {
286 let mut err = Error::new(ErrorKind::Syntax, "value is not valid unicode");
287 err.set_attachment(EnvVar::new(name.as_str().into()));
288 rv.fail(err);
289 continue;
290 }
291 },
292 };
293 rv.push(name.into(), prefix.len(), value);
294 }
295 rv.finish_vars();
296 rv
297 }
298}
299
300impl<'a> Deserializer<'a> {
301 pub fn from_vars<I, K, V>(prefix: &str, vars: I) -> Deserializer<'a>
307 where
308 I: IntoIterator<Item = (K, V)>,
309 K: Into<Cow<'a, str>>,
310 V: Into<Cow<'a, str>>,
311 {
312 Deserializer::from_vars_with_config(prefix, vars, DeserializerConfig::new())
313 }
314
315 pub fn from_vars_with_config<I, K, V>(
318 prefix: &str,
319 vars: I,
320 config: DeserializerConfig,
321 ) -> Deserializer<'a>
322 where
323 I: IntoIterator<Item = (K, V)>,
324 K: Into<Cow<'a, str>>,
325 V: Into<Cow<'a, str>>,
326 {
327 let mut rv = Deserializer {
328 vars: Vec::new(),
329 error: None,
330 config,
331 };
332 for (name, value) in vars {
333 let name = name.into();
334 if strip_prefix(&name, prefix).is_some() {
335 rv.push(Arc::from(&*name), prefix.len(), Value::Text(value.into()));
336 }
337 }
338 rv.finish_vars();
339 rv
340 }
341
342 fn push(&mut self, name: Arc<str>, prefix_len: usize, value: Value<'a>) {
343 if name.len() > prefix_len {
345 self.vars.push(Var {
346 name,
347 prefix_len,
348 value,
349 });
350 }
351 }
352
353 fn fail(&mut self, err: Error) {
354 if self.error.is_none() {
355 self.error = Some(err);
356 }
357 }
358
359 fn finish_vars(&mut self) {
361 self.vars.sort_by(|a, b| a.name.cmp(&b.name));
362 }
363
364 pub fn config(&self) -> &DeserializerConfig {
366 &self.config
367 }
368
369 pub fn deserialize<T: Deserialize<'a>>(&mut self) -> Result<T, Error> {
374 de::Deserializer::deserialize(self)
375 }
376
377 pub fn deserialize_with<T, F>(&mut self, setup: F) -> Result<T, Error>
382 where
383 T: Deserialize<'a>,
384 F: FnOnce(&mut DeserializeDriver<'_, 'a>),
385 {
386 de::Deserializer::deserialize_with(self, setup)
387 }
388
389 pub fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
401 if !self.config.context.is_empty() {
402 driver.set_default_context(self.config.context.clone());
403 }
404 if let Some(err) = self.error.take() {
405 return Err(err);
406 }
407 let tree = Tree::build(&self.vars, &self.config)?;
408 let state = driver.state_mut();
409 DuplicateKeys::Last.set_default(state);
412 LexicalRules::LENIENT.set_default(state);
413 state.add_error_context::<CurrentVar>();
414 tree.emit(&self.vars, driver)
415 }
416}
417
418impl<'a> de::Deserializer<'a> for Deserializer<'a> {
419 fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
420 Deserializer::drive(self, driver)
421 }
422}
423
424fn strip_prefix<'n>(name: &'n str, prefix: &str) -> Option<&'n str> {
429 if cfg!(windows) {
430 let head = name.get(..prefix.len())?;
431 head.eq_ignore_ascii_case(prefix)
432 .then(|| &name[prefix.len()..])
433 } else {
434 name.strip_prefix(prefix)
435 }
436}
437
438#[cfg(unix)]
440pub(crate) fn os_bytes(value: OsString) -> Option<Vec<u8>> {
441 use std::os::unix::ffi::OsStringExt;
442 Some(value.into_vec())
443}
444
445#[cfg(not(unix))]
446pub(crate) fn os_bytes(_value: OsString) -> Option<Vec<u8>> {
447 None
448}
449
450#[derive(Debug, Default, Clone)]
454struct CurrentVar(Option<Arc<str>>);
455
456impl deser_core::ErrorContext for CurrentVar {
457 fn add_context(err: &mut Error, state: &deser_core::State) {
458 if err.attachment::<EnvVar>().is_some() {
459 return;
460 }
461 if let Some(CurrentVar(Some(name))) = state.event::<CurrentVar>() {
462 err.set_attachment(EnvVar::new(name.clone()));
463 }
464 }
465}
466
467enum NodeKey {
469 Root,
470 Name(String),
471 Index(usize, String),
473}
474
475struct Node {
477 key: NodeKey,
478 name: Option<Arc<str>>,
481 values: Vec<usize>,
483 children: Vec<usize>,
485}
486
487enum Container {
489 Map(Vec<usize>),
490 Seq(Vec<usize>),
491}
492
493#[derive(PartialEq, Eq, Hash)]
495enum ChildId {
496 Name(String),
497 Index(usize),
498}
499
500struct Tree {
502 nodes: Vec<Node>,
503}
504
505impl Tree {
506 fn build(vars: &[Var<'_>], config: &DeserializerConfig) -> Result<Tree, Error> {
507 let mut tree = Tree {
508 nodes: vec![Node {
509 key: NodeKey::Root,
510 name: None,
511 values: Vec::new(),
512 children: Vec::new(),
513 }],
514 };
515 let mut lookup = HashMap::new();
516 let mut segments = Vec::new();
517 for (index, var) in vars.iter().enumerate() {
518 segments.clear();
519 split_name(&var.name[var.prefix_len..], config.separator, &mut segments);
520 if segments.len().saturating_sub(1) > config.max_depth {
521 return Err(var_error(
522 ErrorKind::LimitExceeded,
523 "name is nested too deeply",
524 &var.name,
525 ));
526 }
527 let mut node = 0;
528 for (depth, &(start, end)) in segments.iter().enumerate() {
529 let text = &var.name[var.prefix_len + start..var.prefix_len + end];
530 let text = match config.case {
531 Case::Upper => text.to_ascii_lowercase(),
532 Case::Preserve => text.to_string(),
533 };
534 let id = match text.parse() {
535 Ok(index) if depth > 0 && text.bytes().all(|b| b.is_ascii_digit()) => {
536 ChildId::Index(index)
537 }
538 _ => ChildId::Name(text),
539 };
540 let id = (node, id);
541 node = match lookup.get(&id) {
542 Some(&child) => child,
543 None => {
544 let name = if depth + 1 == segments.len() {
545 var.name.clone()
546 } else {
547 Arc::from(&var.name[..var.prefix_len + end])
548 };
549 tree.child(&mut lookup, id, name)
550 }
551 };
552 }
553 tree.nodes[node].values.push(index);
554 }
555 Ok(tree)
556 }
557
558 fn child(
560 &mut self,
561 lookup: &mut HashMap<(usize, ChildId), usize>,
562 id: (usize, ChildId),
563 name: Arc<str>,
564 ) -> usize {
565 let parent = id.0;
566 let key = match id.1 {
567 ChildId::Name(ref text) => NodeKey::Name(text.clone()),
568 ChildId::Index(index) => NodeKey::Index(index, index.to_string()),
569 };
570 let child = self.nodes.len();
571 self.nodes.push(Node {
572 key,
573 name: Some(name),
574 values: Vec::new(),
575 children: Vec::new(),
576 });
577 self.nodes[parent].children.push(child);
578 lookup.insert(id, child);
579 child
580 }
581
582 fn container(&self, node: &Node) -> Container {
587 let indexes = node
588 .children
589 .iter()
590 .all(|&child| matches!(self.nodes[child].key, NodeKey::Index(..)));
591 if indexes {
592 let mut sorted = node.children.clone();
593 sorted.sort_by_key(|&child| match self.nodes[child].key {
594 NodeKey::Index(index, _) => index,
595 _ => unreachable!(),
596 });
597 let dense = sorted.iter().enumerate().all(|(pos, &child)| {
598 matches!(self.nodes[child].key, NodeKey::Index(index, _) if index == pos)
599 });
600 if dense {
601 return Container::Seq(sorted);
602 }
603 }
604 Container::Map(node.children.clone())
605 }
606
607 fn map_shape(&self, children: &[usize]) -> ContainerShape {
612 let len = children
613 .iter()
614 .map(|&child| self.nodes[child].values.len().max(1))
615 .sum();
616 {
617 let mut shape = ContainerShape::with_len(len);
618 shape.set_multimap(true);
619 shape
620 }
621 }
622
623 fn emit<'a>(
625 &self,
626 vars: &[Var<'a>],
627 driver: &mut DeserializeDriver<'_, 'a>,
628 ) -> Result<(), Error> {
629 struct Frame {
630 children: Vec<usize>,
631 pos: usize,
632 is_map: bool,
633 }
634
635 let root = &self.nodes[0];
636 emit_as(
637 driver,
638 Event::MapStart(self.map_shape(&root.children)),
639 None,
640 )?;
641 let mut stack = vec![Frame {
642 children: root.children.clone(),
643 pos: 0,
644 is_map: true,
645 }];
646
647 while let Some(frame) = stack.last_mut() {
648 let Some(&child) = frame.children.get(frame.pos) else {
649 let event = if frame.is_map {
650 Event::MapEnd
651 } else {
652 Event::SeqEnd
653 };
654 stack.pop();
655 emit_as(driver, event, None)?;
656 continue;
657 };
658 frame.pos += 1;
659 let is_map = frame.is_map;
660 let node = &self.nodes[child];
661 if is_map {
662 emit_key(driver, node)?;
663 }
664
665 match (&node.values[..], node.children.is_empty()) {
666 (&[var], true) => emit_value(driver, &vars[var])?,
667 (&[first, ref rest @ ..], true) if is_map => {
670 emit_value(driver, &vars[first])?;
671 for &var in rest {
672 emit_key(driver, node)?;
673 emit_value(driver, &vars[var])?;
674 }
675 }
676 (values @ [_, _, ..], true) => {
678 let policy = DuplicateKeys::of(driver.state());
679 let var = match policy {
680 DuplicateKeys::First => values[0],
681 DuplicateKeys::Error => {
682 return Err(var_error(
683 ErrorKind::Syntax,
684 "more than one variable for the same index",
685 &vars[values[1]].name,
686 ));
687 }
688 _ => values[values.len() - 1],
689 };
690 emit_value(driver, &vars[var])?;
691 }
692 ([], true) => unreachable!(),
694 ([], false) => {
695 let (children, is_map) = match self.container(node) {
696 Container::Map(children) => (children, true),
697 Container::Seq(children) => (children, false),
698 };
699 let event = if is_map {
700 Event::MapStart(self.map_shape(&children))
701 } else {
702 Event::SeqStart(ContainerShape::with_len(children.len()))
703 };
704 emit_as(driver, event, node.name.as_ref())?;
705 stack.push(Frame {
706 children,
707 pos: 0,
708 is_map,
709 });
710 }
711 (&[var, ..], false) => {
712 return Err(var_error(
713 ErrorKind::Syntax,
714 "variable has a value and nested variables",
715 &vars[var].name,
716 ));
717 }
718 }
719 }
720 Ok(())
721 }
722}
723
724fn emit_key(driver: &mut DeserializeDriver<'_, '_>, node: &Node) -> Result<(), Error> {
726 let key = match node.key {
727 NodeKey::Name(ref text) | NodeKey::Index(_, ref text) => text,
728 NodeKey::Root => unreachable!(),
729 };
730 emit_as(
731 driver,
732 Atom::Lexical(Text::borrowed(key.as_str())),
733 node.name.as_ref(),
734 )
735}
736
737#[inline]
739fn emit_as<'e, E: Into<Event<'e>>>(
740 driver: &mut DeserializeDriver<'_, '_>,
741 event: E,
742 name: Option<&Arc<str>>,
743) -> Result<(), Error> {
744 if let Some(name) = name {
745 driver.state_mut().event_mut::<CurrentVar>().0 = Some(name.clone());
746 }
747 driver.emit(event)
748}
749
750fn emit_value<'a>(driver: &mut DeserializeDriver<'_, 'a>, var: &Var<'a>) -> Result<(), Error> {
753 driver.state_mut().event_mut::<CurrentVar>().0 = Some(var.name.clone());
754 match var.value {
755 Value::Text(Cow::Borrowed(text)) => {
756 driver.emit_borrowed(Atom::Lexical(Text::borrowed(text)))
757 }
758 Value::Text(Cow::Owned(ref text)) => {
759 driver.emit(Atom::Lexical(Text::borrowed(text.as_str())))
760 }
761 Value::Bytes(ref bytes) => driver.emit(Atom::Bytes(Bytes::borrowed(bytes))),
762 }
763}
764
765pub(crate) fn split_name(name: &str, separator: &str, segments: &mut Vec<(usize, usize)>) {
770 if !separator.is_empty() {
771 let mut start = 0;
772 for (pos, _) in name.match_indices(separator) {
773 segments.push((start, pos));
774 start = pos + separator.len();
775 }
776 segments.push((start, name.len()));
777 if segments.iter().all(|&(start, end)| start < end) {
778 return;
779 }
780 segments.clear();
781 }
782 segments.push((0, name.len()));
783}
784
785#[cfg(test)]
786fn split(name: &str, separator: &str) -> Vec<String> {
787 let mut segments = Vec::new();
788 split_name(name, separator, &mut segments);
789 segments
790 .into_iter()
791 .map(|(start, end)| name[start..end].to_string())
792 .collect()
793}
794
795#[test]
796fn test_split_name() {
797 assert_eq!(split("PORT", "__"), ["PORT"]);
798 assert_eq!(
799 split("SERVER__MAX_CONNECTIONS", "__"),
800 ["SERVER", "MAX_CONNECTIONS"]
801 );
802 assert_eq!(split("A__0__B", "__"), ["A", "0", "B"]);
803 assert_eq!(split("A_B", "_"), ["A", "B"]);
804 assert_eq!(split("A__B", ""), ["A__B"]);
805 assert_eq!(split("A___B", "__"), ["A", "_B"]);
807 for name in ["__A", "A__", "A____B", "__"] {
809 assert_eq!(split(name, "__"), [name], "{}", name);
810 }
811}
812
813#[cold]
815fn var_error(kind: ErrorKind, msg: &'static str, name: &Arc<str>) -> Error {
816 let mut err = Error::new(kind, msg);
817 err.set_attachment(EnvVar::new(name.clone()));
818 err
819}