synthphonia/expr/ops/list/map.rs
1use std::cmp::min;
2use std::ops::Not;
3
4use crate::expr::context::Context;
5use crate::expr::Expr;
6use crate::galloc::{AllocForExactSizeIter, AllocForStr, TryAllocForExactSizeIter};
7use crate::parser::config::Config;
8use crate::utils::F64;
9use crate::{impl_op2, new_op1, new_op2, new_op2_opt, new_op3};
10use derive_more::DebugCustom;
11use itertools::izip;
12use crate::value::Value;
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14/// A struct representing a mapping configuration for expressions.
15///
16/// This structure contains a single field, an optional reference to a static `Expr` instance.
17/// The `Option` type encapsulates the possibility of this reference being `None`, indicating that the mapping may or may not point to a valid expression at any given time.
18/// This flexibility allows for dynamic adjustments within the synthesis process, where certain mappings might be deferred or omitted based on the current context or requirements.
19///
20pub struct Map(pub Option<&'static Expr>);
21
22impl std::hash::Hash for Map {
23 /// Provides a method to calculate the hash of the `Map` structure.
24 ///
25 /// The method takes a mutable reference to a generic hasher `H` and computes the hash by first accessing the internal `Option<&'static Expr>` value.
26 /// If the `Option` is `Some`, it maps the contained expression reference to a raw pointer and incorporates it into the hash calculation.
27 /// This ensures that the hashing process uniquely accounts for the memory address of the expression's reference, enhancing the precision of hash-based collections or algorithms using `Map` instances.
28 ///
29 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
30 self.0.map(|x| x as *const Expr).hash(state);
31 }
32}
33
34impl Map {
35 /// Creates a `Map` instance using the provided configuration.
36 ///
37 /// It retrieves an expression associated with the key `"f"` from the given `Config` object, which may be `None` if the key is not found, and wraps this expression in a `Map`.
38 /// This function assists in initializing a `Map` based on pre-defined configurations, facilitating customizable synthesis processes.
39 ///
40 pub fn from_config(config: &Config) -> Self {
41 Self(config.get_expr("f"))
42 }
43 /// Provides a method to retrieve the name associated with the `Map`.
44 ///
45 /// It returns a static string slice representing the operation's name within the context of the Synthphonia module, specifically identifying the `list.map` functionality.
46 /// This method is likely used to ensure consistency and readability when referring to the mapping operation internally or in debug outputs.
47 ///
48 pub fn name() -> &'static str {
49 "list.map"
50 }
51}
52
53impl std::fmt::Display for Map {
54 /// Formats the `Map` structure for output.
55 ///
56 /// The function checks if the `Map` contains an `Expr` and, if so, formats the output to include the expression with a "list.map" prefix decorated by the expression's debug representation.
57 /// If no expression is present, the output simply includes "list.map".
58 /// This functionality is useful for logging or debugging when visual representation of the mapping operation is required.
59 ///
60 fn fmt(&self,f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 if let Some(e) = self.0 {
62 write!(f, "list.map #f:{:?}", e)
63 } else {
64 write!(f, "list.map")
65 }
66 }
67}
68impl Default for Map {
69 /// Creates a default instance of the type by invoking the `from_config` method with a default configuration.
70 /// This method serves as a convenient way to generate an instance with standard settings, ensuring that if no specific configuration is provided, the type is still initialized in a consistent manner using default parameters.
71 fn default() -> Self {
72 Self::from_config(&Default::default())
73 }
74}
75
76impl crate::forward::enumeration::Enumerator1 for Map {
77 /// Provides a method for the `Map` structure to perform enumeration with given parameters, but currently returns a placeholder result.
78 ///
79 /// This method, `enumerate`, takes as parameters a reference to an instance of `Op1Enum`, a static reference to an `Executor`, and an array of one usize operand.
80 /// However, in its current implementation, it performs no actual enumeration or transformation logic and immediately returns a successful `Result` wrapped in `Ok(())` with an empty tuple as the error state.
81 /// This suggests that further enhancements or a use-case-specific implementation might be forthcoming for this structure within the application's context.
82 ///
83 fn enumerate(&self, this: &'static crate::expr::ops::Op1Enum, exec: &'static crate::forward::executor::Executor, opnt: [usize; 1]) -> Result<(), ()> { Ok(()) }
84}
85
86impl crate::expr::ops::Op1 for Map {
87 /// Calculates and returns the cost of the operation as a constant value.
88 ///
89 /// In this implementation, the method consistently returns `1`, indicating a fixed cost for any instance of the struct, regardless of the contents of the `Option<&'static Expr>` field.
90 /// This could be useful for basic cost computation scenarios where each `Map` instance contributes a uniform cost in the overall synthesis process.
91 ///
92 fn cost(&self) -> usize { 1 }
93 /// Provides a method to evaluate an expression contained within a `Map` structure using a given `Value`.
94 ///
95 /// If the input `Value` is of the type `ListStr`, it iterates over the list, creating a context for each string element that includes the length of the string and the string itself.
96 /// The expression is then evaluated within this context, converting the result to a string.
97 /// The output `Value` is adjusted to be a collection of these string results, and the method returns a tuple indicating success with a `true` boolean and the resultant `Value`.
98 /// If the input `Value` is not a `ListStr`, the method returns `false` and a `Null` `Value`.
99 ///
100 fn try_eval(&self, a1: Value) -> (bool, Value) {
101 let e = self.0.unwrap();
102 if let Value::ListStr(a) = a1 {
103 let a = a.iter().map(|&x| {
104 let ctx = Context::new(x.len(), vec![x.into()], vec![], Value::Null);
105 e.eval(&ctx).to_str()
106 }).galloc_scollect();
107 (true, a.into())
108 } else { (false, Value::Null)}
109 }
110}