Skip to content

Commit

Permalink
Make Attributes extend Iterable[Attribute[_]]
Browse files Browse the repository at this point in the history
  • Loading branch information
iRevive committed Nov 21, 2023
1 parent b821ea7 commit 0277171
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@

package org.typelevel.otel4s.sdk

import cats.Applicative
import cats.Hash
import cats.Monad
import cats.Monoid
import cats.Show
import cats.implicits._
Expand All @@ -31,7 +29,7 @@ import org.typelevel.otel4s.AttributeKey
* @see
* [[https://opentelemetry.io/docs/specs/otel/common/#attribute-collections]]
*/
sealed trait Attributes {
sealed trait Attributes extends Iterable[Attribute[_]] {

/** Returns an attribute for the given attribute name, or `None` if not found.
*/
Expand All @@ -41,31 +39,10 @@ sealed trait Attributes {
*/
def get[T](key: AttributeKey[T]): Option[Attribute[T]]

/** Whether the attributes collection is empty or not.
*/
def isEmpty: Boolean

/** The size of the attributes collection.
*/
def size: Int

/** Whether this attributes collection contains the given key.
*/
def contains(key: AttributeKey[_]): Boolean

/** Applies an operation to each attribute and accumulates the results from
* left to right.
*/
def foldLeft[F[_]: Monad, B](z: B)(f: (B, Attribute[_]) => F[B]): F[B]

/** Checks if the given predicate holds for all attributes in the collection.
*/
def forall[F[_]: Monad](p: Attribute[_] => F[Boolean]): F[Boolean]

/** Applies the given operation to each attribute in the collection.
*/
def foreach[F[_]: Applicative](f: Attribute[_] => F[Unit]): F[Unit]

/** Returns the `Map` representation of the attributes collection.
*/
def toMap: Map[AttributeKey[_], Attribute[_]]
Expand Down Expand Up @@ -208,29 +185,13 @@ object Attributes {
def get[T](key: AttributeKey[T]): Option[Attribute[T]] =
m.get(key).map(_.asInstanceOf[Attribute[T]])

def isEmpty: Boolean = m.isEmpty

def size: Int = m.size

def contains(key: AttributeKey[_]): Boolean = m.contains(key)

def foldLeft[F[_]: Monad, B](z: B)(f: (B, Attribute[_]) => F[B]): F[B] =
m.foldLeft(Monad[F].pure(z)) { (acc, v) =>
acc.flatMap(b => f(b, v._2))
}

def forall[F[_]: Monad](p: Attribute[_] => F[Boolean]): F[Boolean] =
foldLeft(true) { (b, a) =>
if (b) p(a).map(b && _)
else Monad[F].pure(false)
}

def foreach[F[_]: Applicative](f: Attribute[_] => F[Unit]): F[Unit] =
m.foldLeft(Applicative[F].unit)((acc, v) => acc *> f(v._2))

def toMap: Map[AttributeKey[_], Attribute[_]] = m

def toList: List[Attribute[_]] = m.values.toList
def iterator: Iterator[Attribute[_]] = m.values.iterator

override def toList: List[Attribute[_]] = m.values.toList
}

private final class MutableBuilder extends Builder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package org.typelevel.otel4s.sdk

import cats.Id
import cats.Show
import cats.syntax.semigroup._
import munit.ScalaCheckSuite
Expand All @@ -34,7 +33,7 @@ class AttributesProps extends ScalaCheckSuite {
property("Attributes#size is equal to the number of unique keys") {
forAll(listOfAttributes) { attributes =>
val keysSet = attributes.map(_.key).toSet
val attrs = Attributes(attributes: _*)
val attrs = Attributes.fromIterable(attributes)

keysSet.size == attrs.size
}
Expand All @@ -43,7 +42,7 @@ class AttributesProps extends ScalaCheckSuite {
property("Attributes#isEmpty is true when there are no attributes") {
forAll(listOfAttributes) { attributes =>
val keysSet = attributes.map(_.key).toSet
val attrs = Attributes(attributes: _*)
val attrs = Attributes.fromIterable(attributes)

keysSet.isEmpty == attrs.isEmpty
}
Expand All @@ -52,26 +51,26 @@ class AttributesProps extends ScalaCheckSuite {
property("Attributes#contains is true when the key is present") {
forAll(listOfAttributes) { attributes =>
val keysSet = attributes.map(_.key).toSet
val attrs = Attributes(attributes: _*)
val attrs = Attributes.fromIterable(attributes)

keysSet.forall(attrs.contains)
}
}

property("Attributes#foreach iterates over all attributes") {
forAll(listOfAttributes) { attributes =>
val attrs = Attributes(attributes: _*)
val attrs = Attributes.fromIterable(attributes)

var count = 0
attrs.foreach[Id] { _ => count += 1 }
attrs.foreach(_ => count += 1)

count == attrs.size
}
}

property("Attributes#toList returns a list of all attributes") {
forAll(listOfAttributes) { attributes =>
val attrs = Attributes(attributes: _*)
val attrs = Attributes.fromIterable(attributes)
val list = attrs.toList

list.size == attrs.size && list.forall(a => attrs.contains(a.key))
Expand All @@ -80,10 +79,10 @@ class AttributesProps extends ScalaCheckSuite {

property("Attributes#foldLeft folds over all attributes") {
forAll(listOfAttributes) { attributes =>
val attrs = Attributes(attributes: _*)
val attrs = Attributes.fromIterable(attributes)
val list = attrs.toList

val folded = attrs.foldLeft[Id, Int](0) { (acc, _) => acc + 1 }
val folded = attrs.foldLeft[Int](0) { (acc, _) => acc + 1 }

folded == list.size
}
Expand All @@ -93,15 +92,15 @@ class AttributesProps extends ScalaCheckSuite {
"Attributes#forall returns true when all attributes match the predicate"
) {
forAll(listOfAttributes) { attributes =>
val attrs = Attributes(attributes: _*)
val attrs = Attributes.fromIterable(attributes)

attrs.forall[Id](_ => true)
attrs.forall(_ => true)
}
}

property("Attributes#toMap returns a map of all attributes") {
forAll(listOfAttributes) { attributes =>
val attrs = Attributes(attributes: _*)
val attrs = Attributes.fromIterable(attributes)
val map = attrs.toMap

map.size == attrs.size && map.forall { case (k, v) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package org.typelevel.otel4s.sdk

import cats.Id
import cats.Show
import cats.syntax.show._
import munit.ScalaCheckSuite
Expand All @@ -34,7 +33,7 @@ class ResourceProps extends ScalaCheckSuite {
val keys =
resource1.attributes.toMap.keySet ++ resource2.attributes.toMap.keySet

mergedAttrs.size == keys.size && mergedAttrs.forall[Id] { a =>
mergedAttrs.size == keys.size && mergedAttrs.forall { a =>
resource2.attributes
.get(a.key)
.orElse(resource1.attributes.get(a.key))
Expand Down

0 comments on commit 0277171

Please sign in to comment.