diff --git a/src/core/Safety.scala b/src/core/Safety.scala new file mode 100644 index 0000000..1241552 --- /dev/null +++ b/src/core/Safety.scala @@ -0,0 +1,16 @@ +package core + +import scala.scalajs.js + +class Safety private (d: js.Dynamic) extends Selectable: + def selectDynamic(name: String): Any = + js.typeOf(d) match + case "object" => + val v = d.selectDynamic(name) + if js.isUndefined(v) then throw NoSuchFieldException(name) else v + case t => + throw UnsupportedOperationException(s"get $name from $t") + +object Safety: + def apply[T <: Safety](d: js.Dynamic) = new Safety(d).asInstanceOf[T] + def apply[A <: Safety, B](f: A => B): js.Dynamic => B = d => f(Safety[A](d)) diff --git a/src/garmin/read/package.scala b/src/garmin/read/package.scala index 0fb8e81..5f0c351 100644 --- a/src/garmin/read/package.scala +++ b/src/garmin/read/package.scala @@ -3,21 +3,22 @@ package garmin.read import scala.scalajs.js import core.* +import core.Safety -given Read[Gauge.BeatPerMinute, js.Dynamic, Double] = Read: a => - a.averageHR.asInstanceOf[Double].round +given Read[Gauge.BeatPerMinute, js.Dynamic, Double] = Read: + Safety[Lap, Double](_.averageHR.round) -given Read[Gauge.StepPerMinute, js.Dynamic, Double] = Read: a => - a.averageRunCadence.asInstanceOf[Double].round +given Read[Gauge.StepPerMinute, js.Dynamic, Double] = Read: + Safety[Lap, Double](_.averageRunCadence.round) -given Read[Distance, js.Dynamic, Double] = Read: a => - a.distance.asInstanceOf[Double] +given Read[Distance, js.Dynamic, Double] = Read: + Safety[Lap, Double](_.distance.round) -given Read[Duration, js.Dynamic, Double] = Read: a => - a.duration.asInstanceOf[Double] +given Read[Duration, js.Dynamic, Double] = Read: + Safety[Lap, Double](_.duration.round) -given Read[Timestamp, js.Dynamic, String] = Read: a => - a.startTimeGMT.asInstanceOf[String] +given Read[Timestamp, js.Dynamic, String] = Read: + Safety[Lap, String](_.startTimeGMT) given [A](using Read[Distance, A, Double], @@ -41,3 +42,10 @@ given [A](using end given extension (d: Double) private inline def round = js.Math.round(d) + +private type Lap = Safety: + val averageHR: Double + val averageRunCadence: Double + val distance: Double + val duration: Double + val startTimeGMT: String