pyoxidizerlib/starlark/
python_extension_module.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use {
6    super::python_resource::ResourceCollectionContext,
7    python_packaging::{
8        resource::{PythonExtensionModule, PythonResource},
9        resource_collection::PythonResourceAddCollectionContext,
10    },
11    starlark::values::{
12        error::{RuntimeError, UnsupportedOperation, ValueError},
13        {Mutable, TypedValue, Value, ValueResult},
14    },
15    std::sync::{Arc, Mutex, MutexGuard},
16};
17
18#[derive(Debug)]
19pub struct PythonExtensionModuleWrapper {
20    pub em: PythonExtensionModule,
21    pub add_context: Option<PythonResourceAddCollectionContext>,
22}
23
24/// Starlark `Value` wrapper for `PythonExtensionModule`.
25#[derive(Debug, Clone)]
26pub struct PythonExtensionModuleValue {
27    inner: Arc<Mutex<PythonExtensionModuleWrapper>>,
28    name: String,
29}
30
31impl PythonExtensionModuleValue {
32    pub fn new(em: PythonExtensionModule) -> Self {
33        let name = em.name.clone();
34
35        Self {
36            inner: Arc::new(Mutex::new(PythonExtensionModuleWrapper {
37                em,
38                add_context: None,
39            })),
40            name,
41        }
42    }
43
44    pub fn inner(
45        &self,
46        label: &str,
47    ) -> Result<MutexGuard<PythonExtensionModuleWrapper>, ValueError> {
48        self.inner.try_lock().map_err(|e| {
49            ValueError::Runtime(RuntimeError {
50                code: "PYTHON_EXTENSION_MODULE",
51                message: format!("failed to acquire lock: {}", e),
52                label: label.to_string(),
53            })
54        })
55    }
56}
57
58impl ResourceCollectionContext for PythonExtensionModuleValue {
59    fn add_collection_context(
60        &self,
61    ) -> Result<Option<PythonResourceAddCollectionContext>, ValueError> {
62        Ok(self
63            .inner("PythonExtensionModule.add_collection_context()")?
64            .add_context
65            .clone())
66    }
67
68    fn replace_add_collection_context(
69        &mut self,
70        context: PythonResourceAddCollectionContext,
71    ) -> Result<Option<PythonResourceAddCollectionContext>, ValueError> {
72        Ok(self
73            .inner("PythonExtensionModule.replace_add_collection_context()")?
74            .add_context
75            .replace(context))
76    }
77
78    fn as_python_resource(&self) -> Result<PythonResource<'_>, ValueError> {
79        Ok(PythonResource::from(
80            self.inner("PythonExtensionModule.as_python_resource()")?
81                .em
82                .clone(),
83        ))
84    }
85}
86
87impl TypedValue for PythonExtensionModuleValue {
88    type Holder = Mutable<PythonExtensionModuleValue>;
89    const TYPE: &'static str = "PythonExtensionModule";
90
91    fn values_for_descendant_check_and_freeze(&self) -> Box<dyn Iterator<Item = Value>> {
92        Box::new(std::iter::empty())
93    }
94
95    fn to_str(&self) -> String {
96        format!("{}<name={}>", Self::TYPE, self.name)
97    }
98
99    fn to_repr(&self) -> String {
100        self.to_str()
101    }
102
103    fn get_attr(&self, attribute: &str) -> ValueResult {
104        let inner = self.inner(&format!("PythonExtensionModule.{}", attribute))?;
105
106        let v = match attribute {
107            "is_stdlib" => Value::from(inner.em.is_stdlib),
108            "name" => Value::new(inner.em.name.clone()),
109            attr => {
110                drop(inner);
111
112                return if self.add_collection_context_attrs().contains(&attr) {
113                    self.get_attr_add_collection_context(attr)
114                } else {
115                    Err(ValueError::OperationNotSupported {
116                        op: UnsupportedOperation::GetAttr(attr.to_string()),
117                        left: Self::TYPE.to_string(),
118                        right: None,
119                    })
120                };
121            }
122        };
123
124        Ok(v)
125    }
126
127    fn has_attr(&self, attribute: &str) -> Result<bool, ValueError> {
128        Ok(match attribute {
129            "is_stdlib" => true,
130            "name" => true,
131            attr => self.add_collection_context_attrs().contains(&attr),
132        })
133    }
134
135    fn set_attr(&mut self, attribute: &str, value: Value) -> Result<(), ValueError> {
136        if self.add_collection_context_attrs().contains(&attribute) {
137            self.set_attr_add_collection_context(attribute, value)
138        } else {
139            Err(ValueError::OperationNotSupported {
140                op: UnsupportedOperation::SetAttr(attribute.to_string()),
141                left: Self::TYPE.to_owned(),
142                right: None,
143            })
144        }
145    }
146}