Skip to content

Instantly share code, notes, and snippets.

@caente
Last active August 29, 2015 14:21
Show Gist options
  • Save caente/ace1a18e815944799bda to your computer and use it in GitHub Desktop.
Save caente/ace1a18e815944799bda to your computer and use it in GitHub Desktop.
case class Stretch(
before: Int,
after: Int
)
case class MidnightRange(
start: Int,
end: Int
)
sealed trait Stretched
def Stretched[A]( a: A ): A @@ Stretched = Tag[A, Stretched]( a )
sealed trait MidnightRangeValue
sealed trait Start extends MidnightRangeValue
def Start( i: Int ): Int @@ Start = Tag[Int, Start]( i )
sealed trait End extends MidnightRangeValue
def End( i: Int ): Int @@ End = Tag[Int, End]( i )
implicit class StretchExtensions( val stretch: Stretch ) extends AnyVal {
def taggedStart: Int @@ Start =
Start( stretch.before )
def taggedEnd: Int @@ End =
End( stretch.after )
}
implicit class MidnightRangeExtensions( val m: MidnightRange ) extends AnyVal {
def taggedStart: Int @@ Start =
Start( m.start )
def taggedEnd: Int @@ End =
End( m.end )
}
trait Stretchable[A <: MidnightRangeValue] {
def stretch( v: Int @@ A, delta: Int @@ A ): Int @@ A
def insideBound( v: Int @@ A ): Boolean
}
object Stretchable {
def apply[A <: MidnightRangeValue: Stretchable]: Stretchable[A] = implicitly[Stretchable[A]]
implicit object StrechStart extends Stretchable[Start] {
val lowerStretchBound = DateTimeConstants.MILLIS_PER_HOUR * 8
def stretch( v: Int @@ Start, delta: Int @@ Start ): Int @@ Start =
Start( Tag.unwrap( v ) - Tag.unwrap( delta ) )
def insideBound( v: Int @@ Start ): Boolean =
Tag.unwrap( v ) >= lowerStretchBound
}
implicit object StrechEnd extends Stretchable[End] {
val upperStretchBound = DateTimeConstants.MILLIS_PER_HOUR * 20
def stretch( v: Int @@ End, delta: Int @@ End ): Int @@ End =
End( Tag.unwrap( v ) + Tag.unwrap( delta ) )
def insideBound( v: Int @@ End ): Boolean =
Tag.unwrap( v ) <= upperStretchBound
}
}
def stretch[A <: MidnightRangeValue: Stretchable]( v: Int @@ A, delta: Int @@ A ): Int @@ A @@ Stretched = {
val value = Stretchable[A].stretch( v, delta )
if ( Stretchable[A].insideBound( value ) ) Stretched( value )
else Stretched( v )
}
def stretchedMidnightRange( start: Int @@ Start @@ Stretched, end: Int @@ End @@ Stretched ): MidnightRange @@ Stretched =
Stretched( MidnightRange(
Tag.unwrap( Tag.unwrap( start ) ),
Tag.unwrap( Tag.unwrap( end ) )
) )
def stretchMidnightRange( m: MidnightRange, s: Stretch ): MidnightRange @@ Stretched = {
val start = stretch( m.taggedStart, s.taggedStart )
val end = stretch( m.taggedEnd, s.taggedEnd )
stretchedMidnightRange( start, end )
}
@caente
Copy link
Author

caente commented May 14, 2015

maybe I went too far?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment