lux_lib/lua_rockspec/
dependency.rs

1use std::{collections::HashMap, convert::Infallible, path::PathBuf};
2
3use mlua::{FromLua, IntoLua};
4use path_slash::PathBufExt;
5use serde::Deserialize;
6
7use super::{
8    DisplayAsLuaKV, DisplayLuaKV, DisplayLuaValue, PartialOverride, PerPlatform,
9    PlatformOverridable,
10};
11
12/// Can be defined in a [platform-agnostic](https://github.com/luarocks/luarocks/wiki/platform-agnostic-external-dependencies) manner
13#[derive(Debug, PartialEq, Clone, Deserialize, Default)]
14pub struct ExternalDependencySpec {
15    /// A header file, e.g. "foo.h"
16    pub(crate) header: Option<PathBuf>,
17    /// A library file, e.g. "libfoo.so"
18    pub(crate) library: Option<PathBuf>,
19}
20
21impl IntoLua for ExternalDependencySpec {
22    fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<mlua::Value> {
23        let table = lua.create_table()?;
24        if let Some(path) = self.header {
25            table.set("header", path.to_slash_lossy().to_string())?;
26        }
27        if let Some(path) = self.library {
28            table.set("library", path.to_slash_lossy().to_string())?;
29        }
30        Ok(mlua::Value::Table(table))
31    }
32}
33
34impl FromLua for ExternalDependencySpec {
35    fn from_lua(value: mlua::Value, _lua: &mlua::Lua) -> mlua::Result<Self> {
36        if let mlua::Value::Table(table) = value {
37            let header = table.get("header")?;
38            let library = table.get("library")?;
39
40            Ok(Self { header, library })
41        } else {
42            Err(mlua::Error::FromLuaConversionError {
43                from: "ExternalDependencySpec",
44                to: "table".to_string(),
45                message: Some("Expected a table".to_string()),
46            })
47        }
48    }
49}
50
51impl PartialOverride for ExternalDependencySpec {
52    type Err = Infallible;
53
54    fn apply_overrides(&self, override_val: &Self) -> Result<Self, Self::Err> {
55        Ok(Self {
56            header: override_val.header.clone().or(self.header.clone()),
57            library: override_val.library.clone().or(self.header.clone()),
58        })
59    }
60}
61
62impl PartialOverride for HashMap<String, ExternalDependencySpec> {
63    type Err = Infallible;
64
65    fn apply_overrides(&self, override_map: &Self) -> Result<Self, Self::Err> {
66        let mut result = Self::new();
67        for (key, value) in self {
68            result.insert(
69                key.clone(),
70                override_map
71                    .get(key)
72                    .map(|override_val| value.apply_overrides(override_val).expect("infallible"))
73                    .unwrap_or(value.clone()),
74            );
75        }
76        for (key, value) in override_map {
77            if !result.contains_key(key) {
78                result.insert(key.clone(), value.clone());
79            }
80        }
81        Ok(result)
82    }
83}
84
85impl PlatformOverridable for HashMap<String, ExternalDependencySpec> {
86    type Err = Infallible;
87
88    fn on_nil<T>() -> Result<super::PerPlatform<T>, <Self as PlatformOverridable>::Err>
89    where
90        T: PlatformOverridable,
91        T: Default,
92    {
93        Ok(PerPlatform::default())
94    }
95}
96
97pub(crate) struct ExternalDependencies<'a>(pub(crate) &'a HashMap<String, ExternalDependencySpec>);
98
99impl DisplayAsLuaKV for ExternalDependencies<'_> {
100    fn display_lua(&self) -> DisplayLuaKV {
101        DisplayLuaKV {
102            key: "external_dependencies".to_string(),
103            value: DisplayLuaValue::Table(
104                self.0
105                    .iter()
106                    .map(|(key, value)| {
107                        let mut value_entries = Vec::new();
108                        if let Some(path) = &value.header {
109                            value_entries.push(DisplayLuaKV {
110                                key: "header".to_string(),
111                                value: DisplayLuaValue::String(path.to_slash_lossy().to_string()),
112                            });
113                        }
114                        if let Some(path) = &value.library {
115                            value_entries.push(DisplayLuaKV {
116                                key: "library".to_string(),
117                                value: DisplayLuaValue::String(path.to_slash_lossy().to_string()),
118                            });
119                        }
120                        DisplayLuaKV {
121                            key: key.clone(),
122                            value: DisplayLuaValue::Table(value_entries),
123                        }
124                    })
125                    .collect(),
126            ),
127        }
128    }
129}