Skip to main content

kinetics_parser/
function.rs

1use crate::params::Params;
2use color_eyre::eyre::{self, ContextCompat};
3use serde::{Deserialize, Serialize};
4use std::{fmt::Display, path::PathBuf};
5
6/// The kind of function
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub enum Role {
9    Endpoint,
10    Cron,
11    Worker,
12}
13
14impl Display for Role {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        let str = match self {
17            Role::Endpoint => "endpoint",
18            Role::Cron => "cron",
19            Role::Worker => "worker",
20        };
21
22        write!(f, "{}", str)
23    }
24}
25
26/// Represents a function in the source code
27#[derive(Debug, Clone)]
28pub struct ParsedFunction {
29    /// Name of the function, parsed from the function definition
30    pub rust_function_name: String,
31
32    /// Path to the file where function is defined
33    pub relative_path: PathBuf,
34
35    /// The name of the package where function is defined
36    pub pkg_name: String,
37
38    /// Path to the package where function is defined
39    pub pkg_rel_path: PathBuf,
40
41    /// The kind of function (endpoint, cron, or worker), without parameters
42    pub role: Role,
43
44    /// The workload-specific parameters parsed from the kinetics macro attribute
45    pub params: Params,
46}
47
48impl Display for ParsedFunction {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        write!(
51            f,
52            "{}",
53            self.pkg_rel_path
54                .join(&self.relative_path)
55                .to_string_lossy()
56        )
57    }
58}
59
60impl ParsedFunction {
61    /// Convert a collection of path segments
62    /// to CamelCase name
63    pub fn to_local_name(paths: &[&str]) -> String {
64        paths
65            .iter()
66            .flat_map(|path| {
67                path.split(&['.', '/'])
68                    .filter(|s| !s.eq(&"rs"))
69                    .map(|s| match s.chars().next() {
70                        Some(first) => first.to_uppercase().collect::<String>() + &s[1..],
71                        None => String::new(),
72                    })
73            })
74            .collect::<String>()
75    }
76
77    /// Generate lambda function name out of Rust function name or macro attribute
78    ///
79    /// By default use the Rust function plus crate path as the function name. Convert
80    /// some-name to SomeName, and do other transformations in order to comply with Lambda
81    /// function name requirements.
82    pub fn func_name(&self, is_local: bool) -> eyre::Result<String> {
83        let rust_name = &self.rust_function_name;
84        let default_func_name = Self::to_local_name(&[
85            &self.pkg_name,
86            self.relative_path
87                .strip_prefix("src")?
88                .to_str()
89                .wrap_err_with(|| {
90                    format!(
91                        "Failed converting func path to str: `{:?}`",
92                        self.relative_path
93                    )
94                })?,
95            rust_name,
96        ]);
97        let name = self.params.name().unwrap_or(&default_func_name);
98
99        if name.len() > 64 {
100            Err(eyre::eyre!(
101                "Function name is longer than 64 chars: {}",
102                name
103            ))
104        } else {
105            // TODO Check the name for uniqueness
106            Ok(format!("{}{}", name, if is_local { "Local" } else { "" }))
107        }
108    }
109}