1use anyhow::{anyhow, Context, Result};
2use gpui::{fonts, AssetSource, FontCache};
3use parking_lot::Mutex;
4use serde_json::{Map, Value};
5use std::{collections::HashMap, fmt, mem, sync::Arc};
6
7use super::Theme;
8
9pub struct ThemeRegistry {
10 assets: Box<dyn AssetSource>,
11 themes: Mutex<HashMap<String, Arc<Theme>>>,
12 theme_data: Mutex<HashMap<String, Arc<Value>>>,
13 font_cache: Arc<FontCache>,
14}
15
16#[derive(Default)]
17struct KeyPathReferenceSet {
18 references: Vec<KeyPathReference>,
19 reference_ids_by_source: Vec<usize>,
20 reference_ids_by_target: Vec<usize>,
21 dependencies: Vec<(usize, usize)>,
22 dependency_counts: Vec<usize>,
23}
24
25#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
26struct KeyPathReference {
27 target: KeyPath,
28 source: KeyPath,
29}
30
31#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
32struct KeyPath(Vec<Key>);
33
34#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
35enum Key {
36 Array(usize),
37 Object(String),
38}
39
40impl ThemeRegistry {
41 pub fn new(source: impl AssetSource, font_cache: Arc<FontCache>) -> Arc<Self> {
42 Arc::new(Self {
43 assets: Box::new(source),
44 themes: Default::default(),
45 theme_data: Default::default(),
46 font_cache,
47 })
48 }
49
50 pub fn list(&self) -> impl Iterator<Item = String> {
51 self.assets.list("themes/").into_iter().filter_map(|path| {
52 let filename = path.strip_prefix("themes/")?;
53 let theme_name = filename.strip_suffix(".toml")?;
54 if theme_name.starts_with('_') {
55 None
56 } else {
57 Some(theme_name.to_string())
58 }
59 })
60 }
61
62 pub fn clear(&self) {
63 self.theme_data.lock().clear();
64 self.themes.lock().clear();
65 }
66
67 pub fn get(&self, name: &str) -> Result<Arc<Theme>> {
68 if let Some(theme) = self.themes.lock().get(name) {
69 return Ok(theme.clone());
70 }
71
72 let theme_data = self.load(name, true)?;
73 let mut theme: Theme = fonts::with_font_cache(self.font_cache.clone(), || {
74 serde_path_to_error::deserialize(theme_data.as_ref())
75 })?;
76
77 theme.name = name.into();
78 let theme = Arc::new(theme);
79 self.themes.lock().insert(name.to_string(), theme.clone());
80 Ok(theme)
81 }
82
83 fn load(&self, name: &str, evaluate_references: bool) -> Result<Arc<Value>> {
84 if let Some(data) = self.theme_data.lock().get(name) {
85 return Ok(data.clone());
86 }
87
88 let asset_path = format!("themes/{}.toml", name);
89 let source_code = self
90 .assets
91 .load(&asset_path)
92 .with_context(|| format!("failed to load theme file {}", asset_path))?;
93
94 let mut theme_data: Map<String, Value> = toml::from_slice(source_code.as_ref())
95 .with_context(|| format!("failed to parse {}.toml", name))?;
96
97 // If this theme extends another base theme, deeply merge it into the base theme's data
98 if let Some(base_name) = theme_data
99 .get("extends")
100 .and_then(|name| name.as_str())
101 .map(str::to_string)
102 {
103 let base_theme_data = self
104 .load(&base_name, false)
105 .with_context(|| format!("failed to load base theme {}", base_name))?
106 .as_ref()
107 .clone();
108 if let Value::Object(mut base_theme_object) = base_theme_data {
109 deep_merge_json(&mut base_theme_object, theme_data);
110 theme_data = base_theme_object;
111 }
112 }
113
114 // Find all of the key path references in the object, and then sort them according
115 // to their dependencies.
116 if evaluate_references {
117 let mut key_path = KeyPath::default();
118 let mut references = KeyPathReferenceSet::default();
119 for (key, value) in theme_data.iter() {
120 key_path.0.push(Key::Object(key.clone()));
121 find_references(value, &mut key_path, &mut references);
122 key_path.0.pop();
123 }
124 let sorted_references = references
125 .top_sort()
126 .map_err(|key_paths| anyhow!("cycle for key paths: {:?}", key_paths))?;
127
128 // Now update objects to include the fields of objects they extend
129 for KeyPathReference { source, target } in sorted_references {
130 if let Some(source) = value_at(&mut theme_data, &source).cloned() {
131 let target = value_at(&mut theme_data, &target).unwrap();
132 if let Value::Object(target_object) = target.take() {
133 if let Value::Object(mut source_object) = source {
134 deep_merge_json(&mut source_object, target_object);
135 *target = Value::Object(source_object);
136 } else {
137 Err(anyhow!("extended key path {} is not an object", source))?;
138 }
139 } else {
140 *target = source;
141 }
142 } else {
143 Err(anyhow!("invalid key path '{}'", source))?;
144 }
145 }
146 }
147
148 let result = Arc::new(Value::Object(theme_data));
149 self.theme_data
150 .lock()
151 .insert(name.to_string(), result.clone());
152
153 Ok(result)
154 }
155}
156
157impl KeyPathReferenceSet {
158 fn insert(&mut self, reference: KeyPathReference) {
159 let id = self.references.len();
160 let source_ix = self
161 .reference_ids_by_source
162 .binary_search_by_key(&&reference.source, |id| &self.references[*id].source)
163 .unwrap_or_else(|i| i);
164 let target_ix = self
165 .reference_ids_by_target
166 .binary_search_by_key(&&reference.target, |id| &self.references[*id].target)
167 .unwrap_or_else(|i| i);
168
169 self.populate_dependencies(id, &reference);
170 self.reference_ids_by_source.insert(source_ix, id);
171 self.reference_ids_by_target.insert(target_ix, id);
172 self.references.push(reference);
173 }
174
175 fn top_sort(mut self) -> Result<Vec<KeyPathReference>, Vec<KeyPath>> {
176 let mut results = Vec::with_capacity(self.references.len());
177 let mut root_ids = Vec::with_capacity(self.references.len());
178
179 // Find the initial set of references that have no dependencies.
180 for (id, dep_count) in self.dependency_counts.iter().enumerate() {
181 if *dep_count == 0 {
182 root_ids.push(id);
183 }
184 }
185
186 while results.len() < root_ids.len() {
187 // Just to guarantee a stable result when the inputs are randomized,
188 // sort references lexicographically in absence of any dependency relationship.
189 root_ids[results.len()..].sort_by_key(|id| &self.references[*id]);
190
191 let root_id = root_ids[results.len()];
192 let root = mem::take(&mut self.references[root_id]);
193 results.push(root);
194
195 // Remove this reference as a dependency from any of its dependent references.
196 if let Ok(dep_ix) = self
197 .dependencies
198 .binary_search_by_key(&root_id, |edge| edge.0)
199 {
200 let mut first_dep_ix = dep_ix;
201 let mut last_dep_ix = dep_ix + 1;
202 while first_dep_ix > 0 && self.dependencies[first_dep_ix - 1].0 == root_id {
203 first_dep_ix -= 1;
204 }
205 while last_dep_ix < self.dependencies.len()
206 && self.dependencies[last_dep_ix].0 == root_id
207 {
208 last_dep_ix += 1;
209 }
210
211 // If any reference no longer has any dependencies, then then mark it as a root.
212 // Preserve the references' original order where possible.
213 for (_, successor_id) in self.dependencies.drain(first_dep_ix..last_dep_ix) {
214 self.dependency_counts[successor_id] -= 1;
215 if self.dependency_counts[successor_id] == 0 {
216 root_ids.push(successor_id);
217 }
218 }
219 }
220 }
221
222 // If any references never became roots, then there are reference cycles
223 // in the set. Return an error containing all of the key paths that are
224 // directly involved in cycles.
225 if results.len() < self.references.len() {
226 let mut cycle_ref_ids = (0..self.references.len())
227 .filter(|id| !root_ids.contains(id))
228 .collect::<Vec<_>>();
229
230 // Iteratively remove any references that have no dependencies,
231 // so that the error will only indicate which key paths are directly
232 // involved in the cycles.
233 let mut done = false;
234 while !done {
235 done = true;
236 cycle_ref_ids.retain(|id| {
237 if self.dependencies.iter().any(|dep| dep.0 == *id) {
238 true
239 } else {
240 done = false;
241 self.dependencies.retain(|dep| dep.1 != *id);
242 false
243 }
244 });
245 }
246
247 let mut cycle_key_paths = Vec::new();
248 for id in cycle_ref_ids {
249 let reference = &self.references[id];
250 cycle_key_paths.push(reference.target.clone());
251 cycle_key_paths.push(reference.source.clone());
252 }
253 cycle_key_paths.sort_unstable();
254 return Err(cycle_key_paths);
255 }
256
257 Ok(results)
258 }
259
260 fn populate_dependencies(&mut self, new_id: usize, new_reference: &KeyPathReference) {
261 self.dependency_counts.push(0);
262
263 // If an existing reference's source path starts with the new reference's
264 // target path, then insert this new reference before that existing reference.
265 for id in Self::reference_ids_for_key_path(
266 &new_reference.target.0,
267 &self.references,
268 &self.reference_ids_by_source,
269 KeyPathReference::source,
270 KeyPath::starts_with,
271 ) {
272 Self::add_dependency(
273 (new_id, id),
274 &mut self.dependencies,
275 &mut self.dependency_counts,
276 );
277 }
278
279 // If an existing reference's target path starts with the new reference's
280 // source path, then insert this new reference after that existing reference.
281 for id in Self::reference_ids_for_key_path(
282 &new_reference.source.0,
283 &self.references,
284 &self.reference_ids_by_target,
285 KeyPathReference::target,
286 KeyPath::starts_with,
287 ) {
288 Self::add_dependency(
289 (id, new_id),
290 &mut self.dependencies,
291 &mut self.dependency_counts,
292 );
293 }
294
295 // If an existing reference's source path is a prefix of the new reference's
296 // target path, then insert this new reference before that existing reference.
297 for prefix in new_reference.target.prefixes() {
298 for id in Self::reference_ids_for_key_path(
299 prefix,
300 &self.references,
301 &self.reference_ids_by_source,
302 KeyPathReference::source,
303 PartialEq::eq,
304 ) {
305 Self::add_dependency(
306 (new_id, id),
307 &mut self.dependencies,
308 &mut self.dependency_counts,
309 );
310 }
311 }
312
313 // If an existing reference's target path is a prefix of the new reference's
314 // source path, then insert this new reference after that existing reference.
315 for prefix in new_reference.source.prefixes() {
316 for id in Self::reference_ids_for_key_path(
317 prefix,
318 &self.references,
319 &self.reference_ids_by_target,
320 KeyPathReference::target,
321 PartialEq::eq,
322 ) {
323 Self::add_dependency(
324 (id, new_id),
325 &mut self.dependencies,
326 &mut self.dependency_counts,
327 );
328 }
329 }
330
331 // If an existing reference's target path is a prefix of the new reference's target path,
332 // then insert this new reference before that existing reference.
333 for prefix in new_reference.target.prefixes() {
334 for id in Self::reference_ids_for_key_path(
335 prefix,
336 &self.references,
337 &self.reference_ids_by_target,
338 KeyPathReference::target,
339 PartialEq::eq,
340 ) {
341 Self::add_dependency(
342 (new_id, id),
343 &mut self.dependencies,
344 &mut self.dependency_counts,
345 );
346 }
347 }
348 }
349
350 // Find all existing references that satisfy a given predicate with respect
351 // to a given key path. Use a sorted array of reference ids in order to avoid
352 // performing unnecessary comparisons.
353 fn reference_ids_for_key_path<'a>(
354 key_path: &[Key],
355 references: &[KeyPathReference],
356 sorted_reference_ids: &'a [usize],
357 reference_attribute: impl Fn(&KeyPathReference) -> &KeyPath,
358 predicate: impl Fn(&KeyPath, &[Key]) -> bool,
359 ) -> impl Iterator<Item = usize> + 'a {
360 let ix = sorted_reference_ids
361 .binary_search_by_key(&key_path, |id| &reference_attribute(&references[*id]).0)
362 .unwrap_or_else(|i| i);
363
364 let mut start_ix = ix;
365 while start_ix > 0 {
366 let reference_id = sorted_reference_ids[start_ix - 1];
367 let reference = &references[reference_id];
368 if !predicate(&reference_attribute(reference), key_path) {
369 break;
370 }
371 start_ix -= 1;
372 }
373
374 let mut end_ix = ix;
375 while end_ix < sorted_reference_ids.len() {
376 let reference_id = sorted_reference_ids[end_ix];
377 let reference = &references[reference_id];
378 if !predicate(&reference_attribute(reference), key_path) {
379 break;
380 }
381 end_ix += 1;
382 }
383
384 sorted_reference_ids[start_ix..end_ix].iter().copied()
385 }
386
387 fn add_dependency(
388 (predecessor, successor): (usize, usize),
389 dependencies: &mut Vec<(usize, usize)>,
390 dependency_counts: &mut Vec<usize>,
391 ) {
392 let dependency = (predecessor, successor);
393 if let Err(i) = dependencies.binary_search(&dependency) {
394 dependencies.insert(i, dependency);
395 }
396 dependency_counts[successor] += 1;
397 }
398}
399
400impl KeyPathReference {
401 fn source(&self) -> &KeyPath {
402 &self.source
403 }
404
405 fn target(&self) -> &KeyPath {
406 &self.target
407 }
408}
409
410impl KeyPath {
411 fn new(string: &str) -> Self {
412 Self(
413 string
414 .split(".")
415 .map(|key| Key::Object(key.to_string()))
416 .collect(),
417 )
418 }
419
420 fn starts_with(&self, other: &[Key]) -> bool {
421 self.0.starts_with(&other)
422 }
423
424 fn prefixes(&self) -> impl Iterator<Item = &[Key]> {
425 (1..self.0.len()).map(move |end_ix| &self.0[0..end_ix])
426 }
427}
428
429impl PartialEq<[Key]> for KeyPath {
430 fn eq(&self, other: &[Key]) -> bool {
431 self.0.eq(other)
432 }
433}
434
435impl fmt::Debug for KeyPathReference {
436 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437 write!(
438 f,
439 "KeyPathReference {{ {} <- {} }}",
440 self.target, self.source
441 )
442 }
443}
444
445impl fmt::Display for KeyPath {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 for (i, key) in self.0.iter().enumerate() {
448 match key {
449 Key::Array(index) => write!(f, "[{}]", index)?,
450 Key::Object(key) => {
451 if i > 0 {
452 ".".fmt(f)?;
453 }
454 key.fmt(f)?;
455 }
456 }
457 }
458 Ok(())
459 }
460}
461
462fn deep_merge_json(base: &mut Map<String, Value>, extension: Map<String, Value>) {
463 for (key, extension_value) in extension {
464 if let Value::Object(extension_object) = extension_value {
465 if let Some(base_object) = base.get_mut(&key).and_then(|value| value.as_object_mut()) {
466 deep_merge_json(base_object, extension_object);
467 } else {
468 base.insert(key, Value::Object(extension_object));
469 }
470 } else {
471 base.insert(key, extension_value);
472 }
473 }
474}
475
476fn find_references(value: &Value, key_path: &mut KeyPath, references: &mut KeyPathReferenceSet) {
477 match value {
478 Value::Array(vec) => {
479 for (ix, value) in vec.iter().enumerate() {
480 key_path.0.push(Key::Array(ix));
481 find_references(value, key_path, references);
482 key_path.0.pop();
483 }
484 }
485 Value::Object(map) => {
486 for (key, value) in map.iter() {
487 if key == "extends" {
488 if let Some(source_path) = value.as_str().and_then(|s| s.strip_prefix("$")) {
489 references.insert(KeyPathReference {
490 source: KeyPath::new(source_path),
491 target: key_path.clone(),
492 });
493 }
494 } else {
495 key_path.0.push(Key::Object(key.to_string()));
496 find_references(value, key_path, references);
497 key_path.0.pop();
498 }
499 }
500 }
501 Value::String(string) => {
502 if let Some(source_path) = string.strip_prefix("$") {
503 references.insert(KeyPathReference {
504 source: KeyPath::new(source_path),
505 target: key_path.clone(),
506 });
507 }
508 }
509 _ => {}
510 }
511}
512
513fn value_at<'a>(object: &'a mut Map<String, Value>, key_path: &KeyPath) -> Option<&'a mut Value> {
514 let mut key_path = key_path.0.iter();
515 if let Some(Key::Object(first_key)) = key_path.next() {
516 let mut cur_value = object.get_mut(first_key);
517 for key in key_path {
518 if let Some(value) = cur_value {
519 match key {
520 Key::Array(ix) => cur_value = value.get_mut(ix),
521 Key::Object(key) => cur_value = value.get_mut(key),
522 }
523 } else {
524 return None;
525 }
526 }
527 cur_value
528 } else {
529 None
530 }
531}
532
533#[cfg(test)]
534mod tests {
535 use super::*;
536 use crate::{test::test_app_state, theme::DEFAULT_THEME_NAME};
537 use gpui::MutableAppContext;
538 use rand::{prelude::StdRng, Rng};
539
540 #[gpui::test]
541 fn test_bundled_themes(cx: &mut MutableAppContext) {
542 let app_state = test_app_state(cx);
543 let mut has_default_theme = false;
544 for theme_name in app_state.themes.list() {
545 let theme = app_state.themes.get(&theme_name).unwrap();
546 if theme.name == DEFAULT_THEME_NAME {
547 has_default_theme = true;
548 }
549 assert_eq!(theme.name, theme_name);
550 }
551 assert!(has_default_theme);
552 }
553
554 #[gpui::test]
555 fn test_theme_extension(cx: &mut MutableAppContext) {
556 let assets = TestAssets(&[
557 (
558 "themes/_base.toml",
559 r##"
560 [ui.active_tab]
561 extends = "$ui.tab"
562 border.color = "#666666"
563 text = "$text_colors.bright"
564
565 [ui.tab]
566 extends = "$ui.element"
567 text = "$text_colors.dull"
568
569 [ui.element]
570 background = "#111111"
571 border = {width = 2.0, color = "#00000000"}
572
573 [editor]
574 background = "#222222"
575 default_text = "$text_colors.regular"
576 "##,
577 ),
578 (
579 "themes/light.toml",
580 r##"
581 extends = "_base"
582
583 [text_colors]
584 bright = "#ffffff"
585 regular = "#eeeeee"
586 dull = "#dddddd"
587
588 [editor]
589 background = "#232323"
590 "##,
591 ),
592 ]);
593
594 let registry = ThemeRegistry::new(assets, cx.font_cache().clone());
595 let theme_data = registry.load("light", true).unwrap();
596 assert_eq!(
597 theme_data.as_ref(),
598 &serde_json::json!({
599 "ui": {
600 "active_tab": {
601 "background": "#111111",
602 "border": {
603 "width": 2.0,
604 "color": "#666666"
605 },
606 "extends": "$ui.tab",
607 "text": "#ffffff"
608 },
609 "tab": {
610 "background": "#111111",
611 "border": {
612 "width": 2.0,
613 "color": "#00000000"
614 },
615 "extends": "$ui.element",
616 "text": "#dddddd"
617 },
618 "element": {
619 "background": "#111111",
620 "border": {
621 "width": 2.0,
622 "color": "#00000000"
623 }
624 }
625 },
626 "editor": {
627 "background": "#232323",
628 "default_text": "#eeeeee"
629 },
630 "extends": "_base",
631 "text_colors": {
632 "bright": "#ffffff",
633 "regular": "#eeeeee",
634 "dull": "#dddddd"
635 }
636 })
637 );
638 }
639
640 #[gpui::test]
641 fn test_nested_extension(cx: &mut MutableAppContext) {
642 let assets = TestAssets(&[(
643 "themes/theme.toml",
644 r##"
645 [a]
646 text = { extends = "$text.0" }
647
648 [b]
649 extends = "$a"
650 text = { extends = "$text.1" }
651
652 [text]
653 0 = { color = "red" }
654 1 = { color = "blue" }
655 "##,
656 )]);
657
658 let registry = ThemeRegistry::new(assets, cx.font_cache().clone());
659 let theme_data = registry.load("theme", true).unwrap();
660 assert_eq!(
661 theme_data
662 .get("b")
663 .unwrap()
664 .get("text")
665 .unwrap()
666 .get("color")
667 .unwrap(),
668 "blue"
669 );
670 }
671
672 #[test]
673 fn test_key_path_reference_set_simple() {
674 let input_references = build_refs(&[
675 ("r", "a"),
676 ("a.b.c", "d"),
677 ("d.e", "f"),
678 ("t.u", "v"),
679 ("v.w", "x"),
680 ("v.y", "x"),
681 ("d.h", "i"),
682 ("v.z", "x"),
683 ("f.g", "d.h"),
684 ]);
685 let expected_references = build_refs(&[
686 ("d.h", "i"),
687 ("f.g", "d.h"),
688 ("d.e", "f"),
689 ("a.b.c", "d"),
690 ("r", "a"),
691 ("v.w", "x"),
692 ("v.y", "x"),
693 ("v.z", "x"),
694 ("t.u", "v"),
695 ])
696 .collect::<Vec<_>>();
697
698 let mut reference_set = KeyPathReferenceSet::default();
699 for reference in input_references {
700 reference_set.insert(reference);
701 }
702 assert_eq!(reference_set.top_sort().unwrap(), expected_references);
703 }
704
705 #[test]
706 fn test_key_path_reference_set_with_cycles() {
707 let input_references = build_refs(&[
708 ("x", "a.b"),
709 ("y", "x.c"),
710 ("a.b.c", "d.e"),
711 ("d.e.f", "g.h"),
712 ("g.h.i", "a"),
713 ]);
714
715 let mut reference_set = KeyPathReferenceSet::default();
716 for reference in input_references {
717 reference_set.insert(reference);
718 }
719
720 assert_eq!(
721 reference_set.top_sort().unwrap_err(),
722 &[
723 KeyPath::new("a"),
724 KeyPath::new("a.b.c"),
725 KeyPath::new("d.e"),
726 KeyPath::new("d.e.f"),
727 KeyPath::new("g.h"),
728 KeyPath::new("g.h.i"),
729 ]
730 );
731 }
732
733 #[gpui::test(iterations = 20)]
734 async fn test_key_path_reference_set_random(mut rng: StdRng) {
735 let examples: &[&[_]] = &[
736 &[
737 ("n.d.h", "i"),
738 ("f.g", "n.d.h"),
739 ("n.d.e", "f"),
740 ("a.b.c", "n.d"),
741 ("r", "a"),
742 ("q.q.q", "r.s"),
743 ("r.t", "q"),
744 ("x.x", "r.r"),
745 ("v.w", "x"),
746 ("v.y", "x"),
747 ("v.z", "x"),
748 ("t.u", "v"),
749 ],
750 &[
751 ("w.x.y.z", "t.u.z"),
752 ("x", "w.x"),
753 ("a.b.c1", "x.b1.c"),
754 ("a.b.c2", "x.b2.c"),
755 ],
756 &[
757 ("x.y", "m.n.n.o.q"),
758 ("x.y.z", "m.n.n.o.p"),
759 ("u.v.w", "x.y.z"),
760 ("a.b.c.d", "u.v"),
761 ("a.b.c.d.e", "u.v"),
762 ("a.b.c.d.f", "u.v"),
763 ("a.b.c.d.g", "u.v"),
764 ],
765 ];
766
767 for example in examples {
768 let expected_references = build_refs(example).collect::<Vec<_>>();
769 let mut input_references = expected_references.clone();
770 input_references.sort_by_key(|_| rng.gen_range(0..1000));
771 let mut reference_set = KeyPathReferenceSet::default();
772 for reference in input_references {
773 reference_set.insert(reference);
774 }
775 assert_eq!(reference_set.top_sort().unwrap(), expected_references);
776 }
777 }
778
779 fn build_refs<'a>(rows: &'a [(&str, &str)]) -> impl Iterator<Item = KeyPathReference> + 'a {
780 rows.iter().map(|(target, source)| KeyPathReference {
781 target: KeyPath::new(target),
782 source: KeyPath::new(source),
783 })
784 }
785
786 struct TestAssets(&'static [(&'static str, &'static str)]);
787
788 impl AssetSource for TestAssets {
789 fn load(&self, path: &str) -> Result<std::borrow::Cow<[u8]>> {
790 if let Some(row) = self.0.iter().find(|e| e.0 == path) {
791 Ok(row.1.as_bytes().into())
792 } else {
793 Err(anyhow!("no such path {}", path))
794 }
795 }
796
797 fn list(&self, prefix: &str) -> Vec<std::borrow::Cow<'static, str>> {
798 self.0
799 .iter()
800 .copied()
801 .filter_map(|(path, _)| {
802 if path.starts_with(prefix) {
803 Some(path.into())
804 } else {
805 None
806 }
807 })
808 .collect()
809 }
810 }
811}