haproxy_config/config/
global.rs1use crate::config::error::Error;
2use crate::line::borrowed::Line;
3
4use super::super::section::borrowed::Section;
5
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, Default, PartialEq, Eq)]
9pub struct Global {
10 pub config: HashMap<String, Option<String>>,
11 pub user: Option<String>,
13 pub group: Option<String>,
15}
16
17impl<'a> TryFrom<&'a [Section<'a>]> for Global {
18 type Error = Error;
19
20 fn try_from(entries: &'a [Section<'_>]) -> Result<Self, Self::Error> {
21 let global_entries: Vec<_> = entries
22 .iter()
23 .filter(|e| matches!(e, Section::Global { .. }))
24 .collect();
25
26 if global_entries.len() > 1 {
27 return Err(Error::multiple_global_entries(global_entries));
28 }
29
30 let Some(Section::Global{ lines, .. }) = global_entries.first() else {
31 return Ok(Global::default());
32 };
33
34 let mut config = HashMap::new();
35 let mut user_lines = Vec::new();
36 let mut group_lines = Vec::new();
37 let mut other = Vec::new();
38
39 for line in lines
40 .iter()
41 .filter(|l| !matches!(l, Line::Blank | Line::Comment(_)))
42 {
43 match line {
44 Line::Config { key, value, .. } => {
45 let key = (*key).to_string();
46 let value = value.map(ToOwned::to_owned);
47 config.insert(key, value);
48 }
49 Line::SysUser { .. } => {
50 user_lines.push(line);
51 }
52 Line::Group { .. } => {
53 group_lines.push(line);
54 }
55 wrong => other.push(wrong),
56 }
57 }
58
59 if !other.is_empty() {
60 return Err(Error::wrong_global_lines(other));
61 }
62
63 let (user, group) = extract_sys_user_group(user_lines, group_lines)?;
64
65 Ok(Global {
66 config,
67 user,
68 group,
69 })
70 }
71}
72
73fn extract_sys_user_group<'a>(
74 mut user_lines: Vec<&'a Line>,
75 mut group_lines: Vec<&'a Line>,
76) -> Result<(Option<String>, Option<String>), Error> {
77 if user_lines.len() > 1 {
78 return Err(Error::multiple_sys_users(user_lines));
79 }
80 if group_lines.len() > 1 {
81 return Err(Error::multiple_sys_groups(group_lines));
82 }
83
84 let user = match user_lines.pop() {
85 None => None,
86 Some(Line::SysUser { name, .. }) => Some((*name).to_string()),
87 _wrong => unreachable!(),
88 };
89
90 let group = match group_lines.pop() {
91 None => None,
92 Some(line @ Line::Group { name, users, .. }) => {
93 if !users.is_empty() {
94 return Err(Error::sys_group_has_users(line));
95 }
96 Some((*name).to_string())
97 }
98 _wrong => unreachable!(),
99 };
100
101 Ok((user, group))
102}