Skip to content

Commit

Permalink
Implement httpLabel with nom
Browse files Browse the repository at this point in the history
Move to `nom` to implement httpLabel instead of using regexes.

Issue: #938

Signed-off-by: Daniele Ahmed <ahmeddan@amazon.com>
  • Loading branch information
82marbag committed Dec 18, 2021
1 parent 341194e commit e6eb95a
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ object ServerCargoDependency {
val AsyncTrait: CargoDependency = CargoDependency("async-trait", CratesIo("0.1"))
val AxumCore: CargoDependency = CargoDependency("axum-core", CratesIo("0.1"))
val FuturesUtil: CargoDependency = CargoDependency("futures-util", CratesIo("0.3"))
val Nom: CargoDependency = CargoDependency("nom", CratesIo("7"))
val PinProjectLite: CargoDependency = CargoDependency("pin-project-lite", CratesIo("0.2"))
val SerdeUrlEncoded: CargoDependency = CargoDependency("serde_urlencoded", CratesIo("0.7"))
val Tower: CargoDependency = CargoDependency("tower", CratesIo("0.4"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ private class ServerHttpProtocolImplGenerator(
"HttpBody" to CargoDependency.HttpBody.asType(),
"Hyper" to CargoDependency.Hyper.asType(),
"LazyStatic" to CargoDependency.LazyStatic.asType(),
"Nom" to ServerCargoDependency.Nom.asType(),
"PercentEncoding" to CargoDependency.PercentEncoding.asType(),
"Regex" to CargoDependency.Regex.asType(),
"SerdeUrlEncoded" to ServerCargoDependency.SerdeUrlEncoded.asType(),
Expand Down Expand Up @@ -577,42 +578,47 @@ private class ServerHttpProtocolImplGenerator(
if (pathBindings.isEmpty()) {
return
}
val pattern = StringBuilder()
val httpTrait = httpBindingResolver.httpTrait(operationShape)
httpTrait.uri.segments.forEach {
pattern.append("/")
if (it.isLabel) {
pattern.append("(?P<${it.content}>")
if (it.isGreedyLabel) {
pattern.append(".+")
} else {
pattern.append("[^/]+")
}
pattern.append(")")
} else {
pattern.append(it.content)
}
}
with(writer) {
rustTemplate(
"""
#{LazyStatic}::lazy_static! {
static ref RE: #{Regex}::Regex = #{Regex}::Regex::new("$pattern").unwrap();
}
let input_string = request.uri().path();
""".trimIndent(),
*codegenScope,
)
rustBlock("if let Some(captures) = RE.captures(request.uri().path())") {
pathBindings.forEach {
val deserializer = generateParsePercentEncodedStrFn(it)
httpTrait.uri.segments.forEachIndexed { index, segment ->
val name = segment.content
val bindings = pathBindings.filter { it.memberName == name }
val tag = """#{Nom}::bytes::complete::tag("/")"""
val nomParser =
if (segment.isLabel && segment.isGreedyLabel) {
"#{Nom}::combinator::rest"
} else if (segment.isLabel) {
"#{Nom}::branch::alt((" +
"""#{Nom}::bytes::complete::take_until1("/"),""" +
"#{Nom}::combinator::rest))"
} else {
"#{Nom}::bytes::complete::tag(${segment.content.dq()})"
}
val inputStringPrefix = if (index == httpTrait.uri.segments.size - 1) {"_"} else {""}
if (bindings.isEmpty()) {
rustTemplate(
"""
if let Some(m) = captures.name("${it.locationName}") {
input = input.${it.member.setterName()}(
#{deserializer}(m.as_str())?
);
}
let (${inputStringPrefix}input_string, (_tag, _m)) = #{Nom}::sequence::tuple::<&str, _, (_, _), _>(($tag, ${nomParser}))(input_string).unwrap();
""".trimIndent(),
*codegenScope,
)
} else {
val binding = bindings[0]
val deserializer = generateParsePercentEncodedStrFn(binding)
rustTemplate(
"""
let (${inputStringPrefix}input_string, (_tag, m)) = #{Nom}::sequence::tuple::<&str, _, (_, _), _>(($tag, ${nomParser}))(input_string).unwrap();
input = input.${binding.member.setterName()}(
#{deserializer}(m)?
);
""".trimIndent(),
*codegenScope,
"deserializer" to deserializer,
)
}
Expand Down

0 comments on commit e6eb95a

Please sign in to comment.