All Downloads are FREE. Search and download functionalities are using the official Maven repository.

smithy4s.http.matchPath.scala Maven / Gradle / Ivy

There is a newer version: 0.19.0-41-91762fb
Show newest version
/*
 *  Copyright 2021-2024 Disney Streaming
 *
 *  Licensed under the Tomorrow Open Source Technology License, Version 1.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     https://disneystreaming.github.io/TOST-1.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package smithy4s.http

import scala.annotation.tailrec

import PathSegment._
object matchPath extends smithy4s.ScalaCompat {

  def apply(
      path: List[PathSegment],
      received: IndexedSeq[String]
  ): Option[Map[String, String]] = {
    val size = received.length
    @tailrec
    def matchPathAux(
        path: List[PathSegment],
        i: Int,
        acc: Map[String, String],
        greedyAcc: List[String]
    ): Option[Map[String, String]] =
      path match {
        case Nil if i >= size => Some(acc)
        case StaticSegment(value) :: lt
            if i < size && compareStrings(value, received(i)) =>
          matchPathAux(lt, i + 1, acc, Nil)
        case (LabelSegment(name) :: lt) if i < size =>
          matchPathAux(lt, i + 1, acc + (name -> received(i)), Nil)
        case (GreedySegment(name) :: StaticSegment(value) :: lt)
            if i < size && compareStrings(
              value,
              received(i)
            ) && greedyAcc.nonEmpty =>
          val value = greedyAcc.reverse.mkString("/")
          matchPathAux(lt, i + 1, acc + (name -> value), Nil)
        case p @ (GreedySegment(_) :: Nil) if i < size =>
          matchPathAux(p, i + 1, acc, received(i) :: greedyAcc)
        case GreedySegment(name) :: Nil if greedyAcc.nonEmpty =>
          val value = greedyAcc.reverse.mkString("/")
          Some(acc + (name -> value))
        case _ => None
      }
    matchPathAux(path, 0, Map.empty, List.empty)
  }

  private[http] def make(str: String): IndexedSeq[String] =
    if (str == "" || str == "/")
      IndexedSeq.empty
    else {
      val segments = str.split("/", -1)
      val length = segments.length
      // .head/.last is safe because split always returns non-empty array
      val start = if (segments.head.isEmpty()) 1 else 0
      val end =
        if (length > 1 && segments.last.isEmpty()) length - 1 else length
      val resultArray =
        if (start > 0 || end < length) segments.slice(start, end)
        else segments
      unsafeWrapArray(resultArray)
    }

  private def compareStrings(left: String, right: String): Boolean = {
    (left.hashCode() == right.hashCode()) &&
    left == right
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy