Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,15 @@ lazy val rootProject = (project in file("."))
.aggregate(projectAggregates: _*)

lazy val core = (projectMatrix in file("core"))
.settings(name := "core")
.settings(
name := "core",
libraryDependencies ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((3, _)) => Nil
case _ => Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided)
}
}
)
.jvmPlatform(
scalaVersions = scala2 ++ scala3,
settings = commonJvmSettings
Expand Down
12 changes: 12 additions & 0 deletions core/src/main/scala-2/sttp/attributes/AttributeKeyMacro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package sttp.attributes

import scala.reflect.macros.blackbox

private[attributes] object AttributeKeyMacro {
def apply[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[AttributeKey[T]] = {
import c.universe._
c.Expr[AttributeKey[T]](
q"new _root_.sttp.tapir.AttributeKey(${c.universe.show(implicitly[c.WeakTypeTag[T]].tpe)})"
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package sttp.attributes

trait AttributeKeyMacros {

/** Create an attribute key which contains the full type name of the given type, as inferred by the macro. */
def apply[T]: AttributeKey[T] = macro AttributeKeyMacro[T]
}
18 changes: 18 additions & 0 deletions core/src/main/scala-3/sttp/attributes/AttributeKeyMacros.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package sttp.attributes

import scala.quoted.*

trait AttributeKeyMacros {

/** Create an attribute key which contains the full type name of the given type, as inferred by the macro. */
inline def apply[T]: AttributeKey[T] = ${ AttributeKeyMacros[T] }
}

private[attributes] object AttributeKeyMacros {
def apply[T: Type](using q: Quotes): Expr[AttributeKey[T]] = {
import quotes.reflect.*
val t = TypeRepr.of[T]

'{ new AttributeKey[T](${ Expr(t.show) }) }
}
}
20 changes: 20 additions & 0 deletions core/src/main/scala/sttp/attributes/AttributeKey.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package sttp.attributes

/** A key to be used in an [[AttributeMap]]. The key typically stores the full type name of the value of the attribute.
* Keys can be conveniently created using the `AttributeKey[T]` macro in the companion object.
*
* @param typeName
* The fully qualified name of `T`.
* @tparam T
* Type of the value of the attribute.
*/
class AttributeKey[T](val typeName: String) {
override def equals(other: Any): Boolean = other match {
case that: AttributeKey[_] => typeName == that.typeName
case _ => false
}

override def hashCode(): Int = typeName.hashCode
}

object AttributeKey extends AttributeKeyMacros
24 changes: 24 additions & 0 deletions core/src/main/scala/sttp/attributes/AttributeMap.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package sttp.attributes

/** A type-safe map from [[AttributeKey]] to values of types determined by the key.
*
* An attribute is arbitrary data that is attached to some top-level sttp-defined objects. The data is not interpreted
* by the libraries in any way, and is passed as-is. However, built-in or user-provided extensions and integrations
* might use the attributes to provide their functionality.
*
* Typically, you'll add attributes using an `.attribute` method on the sttp-defined object. Each attribute should
* correspond to a type. The type should be defined by the extension, which uses the attribute, and make it available
* for import.
*/
case class AttributeMap(private val storage: Map[String, Any]) {
def get[T](k: AttributeKey[T]): Option[T] = storage.get(k.typeName).asInstanceOf[Option[T]]
def put[T](k: AttributeKey[T], v: T): AttributeMap = copy(storage = storage + (k.typeName -> v))
def remove[T](k: AttributeKey[T]): AttributeMap = copy(storage = storage - k.typeName)

def isEmpty: Boolean = storage.isEmpty
def nonEmpty: Boolean = storage.nonEmpty
}

object AttributeMap {
val Empty: AttributeMap = AttributeMap(Map.empty)
}
Loading