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

org.coursera.naptime.path.PathKeyParser.scala Maven / Gradle / Ivy

There is a newer version: 0.9.0-alpha5
Show newest version
/*
 * Copyright 2016 Coursera Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 org.coursera.naptime.path

/**
 * An HList for parsers, usually built up automatically via the helper traits (TODO: FILL IN LINKS)
 *
 * @tparam ParseAsType The type this HList of parsers will parse a URL into.
 */
sealed trait PathKeyParser[+ParseAsType <: ParsedPathKey] {
  def parse(path: String): UrlParseResult[ParseAsType]

  /**
   * Concatenates a new parser on the front of the chain (nesting that parser underneath the others)
   * @param resourcePath The resource path (and parse information) for the new resource.
   * @tparam H The new resource has path parameters of this type.
   * @tparam TT This type parameter exists to work around the covariance/contravariance issues with
   *            the return type of this function.
   * @return The new chain.
   */
  def ::[H, TT >: ParseAsType <: ParsedPathKey](
      resourcePath: ResourcePathParser[H]): NestedPathKeyParser[H, TT] =
    new NestedPathKeyParser[H, TT](resourcePath, this)
}

/**
 * HCons for parsers - includes an extra type parameter because we care about both the type we will
 * parse as, as well as the type of the chain itself.
 *
 * @param head All information needed to parse from a URL something of the type H
 * @param tail The rest of the parser chain.
 * @tparam H The type the head of the chain will parse as.
 * @tparam TailParseAsType The tail of the chain will parse as this type
 */
final case class NestedPathKeyParser[
    +H,
    TailParseAsType <: ParsedPathKey](
    head: ResourcePathParser[H],
    tail: PathKeyParser[TailParseAsType])
  extends PathKeyParser[H ::: TailParseAsType] {

  override def toString = s"$head :: $tail"

  override def parse(path: String): UrlParseResult[H ::: TailParseAsType] = {
    parseFinalLevel(path) match {
      case ParseSuccess(restOfUrl, Some(h) ::: rest) =>
        ParseSuccess(restOfUrl, h ::: rest)
      case _ => ParseFailure

    }
  }

  def parseFinalLevel(path: String): UrlParseResult[Option[H] ::: TailParseAsType] = {
    tail.parse(path) match {
      case ParseFailure => ParseFailure
      case ParseSuccess(None, _) => ParseFailure // Nothing left to parse; fail.
      case ParseSuccess(Some(urlThroughParent), tailParse) =>
        head.parseOptUrl(urlThroughParent) match {
          case ParseFailure => ParseFailure
          case ParseSuccess(restOfUrl, elem) =>
            ParseSuccess(restOfUrl, new :::(elem, tailParse))
        }
    }
  }
}

/**
 * The base / end of the PathKey HList-like datastructure.
 */
sealed trait RootPathParser extends PathKeyParser[RootParsedPathKey] {
  override def parse(path: String): UrlParseResult[RootParsedPathKey] =
    ParseSuccess(Some(path), RootParsedPathKey)
}

case object RootPathParser extends RootPathParser




© 2015 - 2025 Weber Informatics LLC | Privacy Policy