lux_lib/lua_rockspec/
dependency.rs1use std::{collections::HashMap, convert::Infallible, path::PathBuf};
2
3use path_slash::PathBufExt;
4use serde::Deserialize;
5
6use super::{
7 DisplayAsLuaKV, DisplayLuaKV, DisplayLuaValue, PartialOverride, PerPlatform,
8 PlatformOverridable,
9};
10
11#[derive(Debug, PartialEq, Clone, Deserialize, Default)]
13pub struct ExternalDependencySpec {
14 pub header: Option<PathBuf>,
16 pub library: Option<PathBuf>,
18}
19
20impl PartialOverride for ExternalDependencySpec {
21 type Err = Infallible;
22
23 fn apply_overrides(&self, override_val: &Self) -> Result<Self, Self::Err> {
24 Ok(Self {
25 header: override_val.header.clone().or(self.header.clone()),
26 library: override_val.library.clone().or(self.header.clone()),
27 })
28 }
29}
30
31impl PartialOverride for HashMap<String, ExternalDependencySpec> {
32 type Err = Infallible;
33
34 fn apply_overrides(&self, override_map: &Self) -> Result<Self, Self::Err> {
35 let mut result = Self::new();
36 for (key, value) in self {
37 result.insert(
38 key.clone(),
39 override_map
40 .get(key)
41 .map(|override_val| value.apply_overrides(override_val).expect("infallible"))
42 .unwrap_or(value.clone()),
43 );
44 }
45 for (key, value) in override_map {
46 if !result.contains_key(key) {
47 result.insert(key.clone(), value.clone());
48 }
49 }
50 Ok(result)
51 }
52}
53
54impl PlatformOverridable for HashMap<String, ExternalDependencySpec> {
55 type Err = Infallible;
56
57 fn on_nil<T>() -> Result<super::PerPlatform<T>, <Self as PlatformOverridable>::Err>
58 where
59 T: PlatformOverridable,
60 T: Default,
61 {
62 Ok(PerPlatform::default())
63 }
64}
65
66pub(crate) struct ExternalDependencies<'a>(pub(crate) &'a HashMap<String, ExternalDependencySpec>);
67
68impl DisplayAsLuaKV for ExternalDependencies<'_> {
69 fn display_lua(&self) -> DisplayLuaKV {
70 DisplayLuaKV {
71 key: "external_dependencies".to_string(),
72 value: DisplayLuaValue::Table(
73 self.0
74 .iter()
75 .map(|(key, value)| {
76 let mut value_entries = Vec::new();
77 if let Some(path) = &value.header {
78 value_entries.push(DisplayLuaKV {
79 key: "header".to_string(),
80 value: DisplayLuaValue::String(path.to_slash_lossy().to_string()),
81 });
82 }
83 if let Some(path) = &value.library {
84 value_entries.push(DisplayLuaKV {
85 key: "library".to_string(),
86 value: DisplayLuaValue::String(path.to_slash_lossy().to_string()),
87 });
88 }
89 DisplayLuaKV {
90 key: key.clone(),
91 value: DisplayLuaValue::Table(value_entries),
92 }
93 })
94 .collect(),
95 ),
96 }
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use ottavino::{Closure, Executor, Fuel, Lua, Value};
103 use ottavino_util::serde::from_value;
104
105 use super::*;
106
107 fn eval_lua<T: serde::de::DeserializeOwned>(code: &str) -> Result<T, ottavino::ExternError> {
108 Lua::core().try_enter(|ctx| {
109 let closure = Closure::load(ctx, None, code.as_bytes())?;
110 let executor = Executor::start(ctx, closure.into(), ());
111 executor.step(ctx, &mut Fuel::with(i32::MAX))?;
112 from_value(executor.take_result::<Value<'_>>(ctx)??).map_err(ottavino::Error::from)
113 })
114 }
115
116 #[test]
117 fn test_external_dependency_spec_from_lua() {
118 let lua_code = r#"
119 return {
120 foo = { header = "foo.h", library = "libfoo.so" },
121 bar = { header = "bar.h" },
122 baz = { library = "libbaz.so" },
123 }
124 "#;
125 let deps: HashMap<String, ExternalDependencySpec> = eval_lua(lua_code).unwrap();
126 assert_eq!(deps.len(), 3);
127 assert_eq!(
128 deps["foo"].header.as_ref().unwrap().to_slash_lossy(),
129 "foo.h"
130 );
131 assert_eq!(
132 deps["foo"].library.as_ref().unwrap().to_slash_lossy(),
133 "libfoo.so"
134 );
135
136 assert_eq!(
137 deps["bar"].header.as_ref().unwrap().to_slash_lossy(),
138 "bar.h"
139 );
140 assert!(deps["bar"].library.is_none());
141
142 assert!(deps["baz"].header.is_none());
143 assert_eq!(
144 deps["baz"].library.as_ref().unwrap().to_slash_lossy(),
145 "libbaz.so"
146 );
147 }
148}