Coverage Report

Created: 2025-01-30 02:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/build/source/nativelink-config/src/lib.rs
Line
Count
Source
1
// Copyright 2024 The NativeLink Authors. All rights reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//    http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
pub mod cas_server;
16
pub mod schedulers;
17
pub mod serde_utils;
18
pub mod stores;
19
20
use std::any::type_name;
21
use std::collections::HashMap;
22
use std::fmt;
23
use std::marker::PhantomData;
24
25
use serde::de::{MapAccess, SeqAccess, Visitor};
26
use serde::{Deserialize, Deserializer};
27
28
#[derive(Debug, Clone, Deserialize)]
29
pub struct NamedConfig<Spec> {
30
    pub name: String,
31
    #[serde(flatten)]
32
    pub spec: Spec,
33
}
34
35
pub type StoreConfig = NamedConfig<crate::stores::StoreSpec>;
36
pub type SchedulerConfig = NamedConfig<crate::schedulers::SchedulerSpec>;
37
38
// TODO(aaronmondal): Remove all the iterator impls and the Deserializer once we
39
//                    fully migrate to the new config schema.
40
pub type StoreConfigs = NamedConfigs<crate::stores::StoreSpec>;
41
pub type SchedulerConfigs = NamedConfigs<crate::schedulers::SchedulerSpec>;
42
43
#[derive(Debug)]
44
pub struct NamedConfigs<T>(pub Vec<NamedConfig<T>>);
45
46
impl<T> NamedConfigs<T> {
47
0
    pub fn iter(&self) -> std::slice::Iter<'_, NamedConfig<T>> {
48
0
        self.0.iter()
49
0
    }
50
}
51
52
impl<T> IntoIterator for NamedConfigs<T> {
53
    type Item = NamedConfig<T>;
54
    type IntoIter = std::vec::IntoIter<Self::Item>;
55
56
2
    fn into_iter(self) -> Self::IntoIter {
57
2
        self.0.into_iter()
58
2
    }
59
}
60
61
impl<'a, T> IntoIterator for &'a NamedConfigs<T> {
62
    type Item = &'a NamedConfig<T>;
63
    type IntoIter = std::slice::Iter<'a, NamedConfig<T>>;
64
65
0
    fn into_iter(self) -> Self::IntoIter {
66
0
        self.0.iter()
67
0
    }
68
}
69
70
struct NamedConfigsVisitor<T> {
71
    phantom: PhantomData<T>,
72
}
73
74
impl<T> NamedConfigsVisitor<T> {
75
2
    fn new() -> Self {
76
2
        NamedConfigsVisitor {
77
2
            phantom: PhantomData,
78
2
        }
79
2
    }
80
}
81
82
impl<'de, T: Deserialize<'de>> Visitor<'de> for NamedConfigsVisitor<T> {
83
    type Value = NamedConfigs<T>;
84
85
0
    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
86
0
        formatter.write_str("a sequence or map of named configs")
87
0
    }
88
89
1
    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
90
1
    where
91
1
        A: SeqAccess<'de>,
92
1
    {
93
1
        let mut vec = Vec::new();
94
3
        while let Some(
config2
) = seq.next_element()
?0
{
  Branch (94:19): [Folded - Ignored]
  Branch (94:19): [True: 2, False: 1]
  Branch (94:19): [Folded - Ignored]
95
2
            vec.push(config);
96
2
        }
97
1
        Ok(NamedConfigs(vec))
98
1
    }
99
100
1
    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
101
1
    where
102
1
        M: MapAccess<'de>,
103
1
    {
104
1
        let config_type = if type_name::<T>().contains("StoreSpec") {
  Branch (104:30): [Folded - Ignored]
  Branch (104:30): [True: 0, False: 1]
  Branch (104:30): [Folded - Ignored]
105
0
            "stores"
106
1
        } else if type_name::<T>().contains("SchedulerSpec") {
  Branch (106:19): [Folded - Ignored]
  Branch (106:19): [True: 0, False: 1]
  Branch (106:19): [Folded - Ignored]
107
0
            "schedulers"
108
        } else {
109
1
            "stores and schedulers"
110
        };
111
1
        eprintln!(
112
1
            r#"
113
1
WARNING: Using deprecated map format for {config_type}. Please migrate to the new array format:
114
1
115
1
  // Old:
116
1
  "stores": {{
117
1
    "SOMESTORE": {{
118
1
      "memory": {{}}
119
1
    }}
120
1
  }},
121
1
  "schedulers": {{
122
1
    "SOMESCHEDULER": {{
123
1
      "simple": {{}}
124
1
    }}
125
1
  }}
126
1
127
1
  // New:
128
1
  "stores": [
129
1
    {{
130
1
      "name": "SOMESTORE",
131
1
      "memory": {{}}
132
1
    }}
133
1
  ],
134
1
  "schedulers": [
135
1
    {{
136
1
      "name": "SOMESCHEDULER",
137
1
      "simple": {{}}
138
1
    }}
139
1
  ]
140
1
"#
141
1
        );
142
1
143
1
        let mut map = HashMap::new();
144
3
        while let Some((
key, value2
)) = access.next_entry()
?0
{
  Branch (144:19): [Folded - Ignored]
  Branch (144:19): [True: 2, False: 1]
  Branch (144:19): [Folded - Ignored]
145
2
            map.insert(key, value);
146
2
        }
147
1
        Ok(NamedConfigs(
148
1
            map.into_iter()
149
2
                .map(|(name, spec)| NamedConfig { name, spec })
150
1
                .collect(),
151
1
        ))
152
1
    }
153
}
154
155
impl<'de, T: Deserialize<'de>> Deserialize<'de> for NamedConfigs<T> {
156
2
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
157
2
    where
158
2
        D: Deserializer<'de>,
159
2
    {
160
2
        deserializer.deserialize_any(NamedConfigsVisitor::new())
161
2
    }
162
}