diff options
author | Alex Auvolat <lx@deuxfleurs.fr> | 2025-01-31 18:18:04 +0100 |
---|---|---|
committer | Alex Auvolat <lx@deuxfleurs.fr> | 2025-01-31 18:18:29 +0100 |
commit | 9fa20d45bebab2a3f66b9721c3643dbd607d944d (patch) | |
tree | 4c5cc3dee19f7cbd9e146a90ef5cbddb052716d5 /src/api/router_macros.rs | |
parent | 9330fd79d3466051394f6d419a247d46da8f5151 (diff) | |
download | garage-9fa20d45bebab2a3f66b9721c3643dbd607d944d.tar.gz garage-9fa20d45bebab2a3f66b9721c3643dbd607d944d.zip |
wip: split garage_api into garage_api_{common,s3,k2v,admin}
Diffstat (limited to 'src/api/router_macros.rs')
-rw-r--r-- | src/api/router_macros.rs | 224 |
1 files changed, 0 insertions, 224 deletions
diff --git a/src/api/router_macros.rs b/src/api/router_macros.rs deleted file mode 100644 index 8f10a4f5..00000000 --- a/src/api/router_macros.rs +++ /dev/null @@ -1,224 +0,0 @@ -/// This macro is used to generate very repetitive match {} blocks in this module -/// It is _not_ made to be used anywhere else -macro_rules! router_match { - (@match $enum:expr , [ $($endpoint:ident,)* ]) => {{ - // usage: router_match {@match my_enum, [ VariantWithField1, VariantWithField2 ..] } - // returns true if the variant was one of the listed variants, false otherwise. - match $enum { - $( - Endpoint::$endpoint { .. } => true, - )* - _ => false - } - }}; - (@extract $enum:expr , $param:ident, [ $($endpoint:ident,)* ]) => {{ - // usage: router_match {@extract my_enum, field_name, [ VariantWithField1, VariantWithField2 ..] } - // returns Some(field_value), or None if the variant was not one of the listed variants. - match $enum { - $( - Endpoint::$endpoint {$param, ..} => Some($param), - )* - _ => None - } - }}; - (@gen_path_parser ($method:expr, $reqpath:expr, $query:expr) - [ - $($meth:ident $path:pat $(if $required:ident)? => $api:ident $(($($conv:ident :: $param:ident),*))?,)* - ]) => {{ - { - #[allow(unused_parens)] - match ($method, $reqpath) { - $( - (&Method::$meth, $path) if true $(&& $query.$required.is_some())? => Endpoint::$api { - $($( - $param: router_match!(@@parse_param $query, $conv, $param), - )*)? - }, - )* - (m, p) => { - return Err(Error::bad_request(format!( - "Unknown API endpoint: {} {}", - m, p - ))) - } - } - } - }}; - (@gen_parser ($keyword:expr, $key:ident, $query:expr, $header:expr), - key: [$($kw_k:ident $(if $required_k:ident)? $(header $header_k:expr)? => $api_k:ident $(($($conv_k:ident :: $param_k:ident),*))?,)*], - no_key: [$($kw_nk:ident $(if $required_nk:ident)? $(if_header $header_nk:expr)? => $api_nk:ident $(($($conv_nk:ident :: $param_nk:ident),*))?,)*]) => {{ - // usage: router_match {@gen_parser (keyword, key, query, header), - // key: [ - // SOME_KEYWORD => VariantWithKey, - // ... - // ], - // no_key: [ - // SOME_KEYWORD => VariantWithoutKey, - // ... - // ] - // } - // See in from_{method} for more detailed usage. - match ($keyword, !$key.is_empty()){ - $( - (Keyword::$kw_k, true) if true $(&& $query.$required_k.is_some())? $(&& $header.contains_key($header_k))? => Ok(Endpoint::$api_k { - $key, - $($( - $param_k: router_match!(@@parse_param $query, $conv_k, $param_k), - )*)? - }), - )* - $( - (Keyword::$kw_nk, false) $(if $query.$required_nk.is_some())? $(if $header.contains($header_nk))? => Ok(Endpoint::$api_nk { - $($( - $param_nk: router_match!(@@parse_param $query, $conv_nk, $param_nk), - )*)? - }), - )* - (kw, _) => Err(Error::bad_request(format!("Invalid endpoint: {}", kw))) - } - }}; - - (@@parse_param $query:expr, query_opt, $param:ident) => {{ - // extract optional query parameter - $query.$param.take().map(|param| param.into_owned()) - }}; - (@@parse_param $query:expr, query, $param:ident) => {{ - // extract mendatory query parameter - $query.$param.take().ok_or_bad_request("Missing argument for endpoint")?.into_owned() - }}; - (@@parse_param $query:expr, opt_parse, $param:ident) => {{ - // extract and parse optional query parameter - // missing parameter is file, however parse error is reported as an error - $query.$param - .take() - .map(|param| param.parse()) - .transpose() - .map_err(|_| Error::bad_request("Failed to parse query parameter"))? - }}; - (@@parse_param $query:expr, parse, $param:ident) => {{ - // extract and parse mandatory query parameter - // both missing and un-parseable parameters are reported as errors - $query.$param.take().ok_or_bad_request("Missing argument for endpoint")? - .parse() - .map_err(|_| Error::bad_request("Failed to parse query parameter"))? - }}; - (@func - $(#[$doc:meta])* - pub enum Endpoint { - $( - $(#[$outer:meta])* - $variant:ident $({ - $($name:ident: $ty:ty,)* - })?, - )* - }) => { - $(#[$doc])* - pub enum Endpoint { - $( - $(#[$outer])* - $variant $({ - $($name: $ty, )* - })?, - )* - } - impl Endpoint { - pub fn name(&self) -> &'static str { - match self { - $(Endpoint::$variant $({ $($name: _,)* .. })? => stringify!($variant),)* - } - } - } - }; -} - -/// This macro is used to generate part of the code in this module. It must be called only one, and -/// is useless outside of this module. -macro_rules! generateQueryParameters { - ( - keywords: [ $($kw_param:expr => $kw_name: ident),* ], - fields: [ $($f_param:expr => $f_name:ident),* ] - ) => { - #[derive(Debug)] - #[allow(non_camel_case_types)] - #[allow(clippy::upper_case_acronyms)] - enum Keyword { - EMPTY, - $( $kw_name, )* - } - - impl std::fmt::Display for Keyword { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Keyword::EMPTY => write!(f, "``"), - $( Keyword::$kw_name => write!(f, "`{}`", $kw_param), )* - } - } - } - - impl Default for Keyword { - fn default() -> Self { - Keyword::EMPTY - } - } - - /// Struct containing all query parameters used in endpoints. Think of it as an HashMap, - /// but with keys statically known. - #[derive(Debug, Default)] - struct QueryParameters<'a> { - keyword: Option<Keyword>, - $( - $f_name: Option<Cow<'a, str>>, - )* - } - - impl<'a> QueryParameters<'a> { - /// Build this struct from the query part of an URI. - fn from_query(query: &'a str) -> Result<Self, Error> { - let mut res: Self = Default::default(); - for (k, v) in url::form_urlencoded::parse(query.as_bytes()) { - match k.as_ref() { - $( - $kw_param => if let Some(prev_kw) = res.keyword.replace(Keyword::$kw_name) { - return Err(Error::bad_request(format!( - "Multiple keywords: '{}' and '{}'", prev_kw, $kw_param - ))); - }, - )* - $( - $f_param => if !v.is_empty() { - if res.$f_name.replace(v).is_some() { - return Err(Error::bad_request(format!( - "Query parameter repeated: '{}'", k - ))); - } - }, - )* - _ => { - if !(k.starts_with("response-") || k.starts_with("X-Amz-")) { - debug!("Received an unknown query parameter: '{}'", k); - } - } - }; - } - Ok(res) - } - - /// Get an error message in case not all parameters where used when extracting them to - /// build an Endpoint variant - fn nonempty_message(&self) -> Option<&str> { - if self.keyword.is_some() { - Some("Keyword not used") - } $( - else if self.$f_name.is_some() { - Some(concat!("'", $f_param, "'")) - } - )* else { - None - } - } - } - } -} - -pub(crate) use generateQueryParameters; -pub(crate) use router_match; |