scodec decode/encode split length field - scala

I am using scodec: https://github.com/scodec/scodec to decode/encode a binary protocol.
I am struggling with a part of the spec where a "length" field is split into two parts by a "moreflag". The moreflag indicates if the length field needs more space.
Example:
Byte 1: identifier bits 8-7, moreFlag bit 6, length bits 5-0 // first length field filled with 0's if moreFlag is false
Byte 2: moreFlag bit 8, length bits 7-0
Byte 3: otherJunk bits 8-0
My problem is I want to encode/decode both of these length fields into a single case class field:
case class Header(totalLength: Int, otherJunk: Int)
I have tried a few different things, but nothing has worked out so far:
implicit val headerCodec: Codec[Header] = (
("identifier" | uint2) :~>:
("moreFlag" | bool).compact >>:~ { meta =>
if (meta.last) {
// more flag enabled, combine lengths somehow
("first length part" | uint(5)) :: ("moreFlag2DontCare" | uint(1) :~>: ("second length part - how to combine?" | uint(7)) :: ("otherJunk" | uint8)
}
else {
("first length part always 0s" | constant(bin"00000")) :: ("moreFlag2DontCare" | uint(1) :~>: ("fullLength" | uint(7)) :: ("otherJunk" | uint8)
}
}
).as[Header]
Am I on the right track here? Thanks!

One way to accomplish this is to use the predefined combinators to define the structure of the binary format -- not the combination logic. Then put the combination logic inside a function passed to xmap.
import scodec._
import bits._
import codecs._
import shapeless._
case class Header(totalLength: Int, otherJunk: Int)
object Header {
implicit val codec: Codec[Header] = {
type Struct = Int :: Boolean :: BitVector :: Boolean :: BitVector :: Int :: HNil
val struct: Codec[Struct] = ("identifier" | uint2) :: ("moreFlag" | bool) :: ("upper length bits" | codecs.bits(5)) :: ("moreFlag2" | bool) :: ("lower length bits" | codecs.bits(7)) :: ("other junk" | uint8)
def to(header: Header): Struct = {
val lengthBits = uint(12).encodeValid(header.totalLength)
val more = !(lengthBits startsWith bin"00000")
0 :: more :: lengthBits.take(5) :: false :: lengthBits.drop(5) :: header.otherJunk :: HNil
}
def from(struct: Struct): Header = struct match {
case id :: moreFlag :: upperLengthBits :: moreFlag2 :: lowerLengthBits :: otherJunk :: HNil =>
val length =
if (moreFlag) uint(12).decodeValidValue(upperLengthBits ++ lowerLengthBits)
else uint(7).decodeValidValue(lowerLengthBits)
Header(length, otherJunk)
}
struct.xmap[Header](from, to)
}
}
Note that the upper and lower length bits are encoded as bits(5) and bits(7) and then manually combined in the from function and decoded. The decoding is safe, despite using the unsafe decodeValidValue, because the uint(12) codec is total on 12-bit inputs -- it is impossible for it to return a left.
However, the to function uses encodeValid, which is clearly unsafe -- e.g., Int.MaxValue will cause an exception. We can fix this with a slightly more complicated version, where the to function returns an Err \/ Struct, and we call widen instead of xmap:
object Header {
implicit val codec: Codec[Header] = {
type Struct = Int :: Boolean :: BitVector :: Boolean :: BitVector :: Int :: HNil
val struct: Codec[Struct] = ("identifier" | uint2) :: ("moreFlag" | bool) :: ("upper length bits" | codecs.bits(5)) :: ("moreFlag2" | bool) :: ("lower length bits" | codecs.bits(7)) :: ("other junk" | uint8)
def to(header: Header): Err \/ Struct = {
uint(12).encode(header.totalLength) map { lengthBits =>
val more = !(lengthBits startsWith bin"00000")
0 :: more :: lengthBits.take(5) :: false :: lengthBits.drop(5) :: header.otherJunk :: HNil
}
}
def from(struct: Struct): Header = struct match {
case id :: moreFlag :: upperLengthBits :: moreFlag2 :: lowerLengthBits :: otherJunk :: HNil =>
val length =
if (moreFlag) uint(12).decodeValidValue(upperLengthBits ++ lowerLengthBits)
else uint(7).decodeValidValue(lowerLengthBits)
Header(length, otherJunk)
}
struct.widen[Header](from, to)
}
}

Related

Extending existing Record type

If I have a record type:
type Rec_ab = { a :: String, b :: Int }
Can I get from it type which is effectfully extended with {c :: Boolean} : { a :: String, b :: Int, c :: Boolean }?
If I had a row, I could do it:
Row_ab = ( a :: String, b :: Int )
Rec_abc = { c :: Boolean | Row_ab }
but if I have a record Rec_ab how this should be solved? I'm not aware of the way of going from Record -> Row.
In general, you can't.
If you need that kind of extensibility, your approach with Row_ab is good enough, but another possible solution is to parametrize the record and then use the parameter to extend it:
type Rec_ab r = { a :: String, b :: Int | r }
type Rec_abc = Rec_ab ( c :: Boolean )
This also allows you to write functions that would work with both Rec_ab and Rec_abc:
add42 :: forall r. Rec_ab r -> Rec_ab r
add42 r = r { b = r.b + 42 }

How to check User input type(Data type) in scala?

I want to check the user input type(Data type) from console in scala? I need to check whether the input data is Int,String,Double, Float.
You can use scala's strongest api match case for this case as
scala> def findDataType(x: Any) = x match {
| case x : String => println("String identified")
| case x : Int => println("Integer identified")
| case x : Float => println("Float identified")
| case x : Double => println("Double identified")
| case _ => println("DataType not identified")
| }
findDataType: (x: Any)Unit
scala> findDataType("abcd")
String identified
scala> findDataType(1)
Integer identified
scala> findDataType(1.0)
Double identified
scala> findDataType(1D)
Double identified
scala> findDataType(1f)
Float identified
scala> findDataType('c')
DataType not identified
We can read in from console and pass to the above function as
scala> findDataType(scala.io.StdIn.readInt())
Integer identified
scala> findDataType(scala.io.StdIn.readLine())
String identified
scala> findDataType(scala.io.StdIn.readFloat())
Float identified
Edited
You can use regex patterns as below(I have used only integer and float)
scala> val INT_PATTERN: String = "^[-+]?[0-9]*$"
INT_PATTERN: String = ^[-+]?[0-9]*$
scala> val FLOAT_PATTERN: String = "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"
FLOAT_PATTERN: String = ^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$
And define the function as
scala> def findDataType(value: Any) = {
| if(value.toString.matches(INT_PATTERN)) println("Integer identified")
| else if(value.toString.matches(FLOAT_PATTERN)) println("Float identified")
| else println("String identified")
| }
findDataType: (value: Any)Unit
Calling the function with scala.io.StdIn.readLine() as below would give the exact datatype
scala> findDataType(scala.io.StdIn.readLine()) // 2 is entered
Integer identified
scala> findDataType(scala.io.StdIn.readLine()) //ab is entered
String identified
scala> findDataType(scala.io.StdIn.readLine()) // 2.1 is entered
Float identified
This can be done for other datatype as well.
Instead of checking the type, I would use the input directly. Try:
val input = scala.io.StdIn.readLine()
if (Try(input.toInt).isSuccess) ... // It is an integer
else if (Try(input.toFloat).isSuccess) ... // It is a float
else if (Try(input.toDouble).isSuccess) ... // It is a double
else ... // No need to convert to string

Scala: filter multiple elements of a list

Assuming I have these scala classes:
Task(id: String, pr: List[PhysicalResource])
PhysicalResource(id: String)
A list: List[PhysicalResource] with these elements:
("PR1" :: "PR2" :: "PR3" :: "PR4" :: Nil)
And this obj: Task object:
("T1", List(PhysicalResource("PR1"), PhysicalResource("PR3")))
I want to return the first two elements (two, because obj.physicalResources.size = 2) of list that match the Physical Resources of the object.
In this example I want to return:
("PR1" :: "PR3" :: Nil)
I am doing this, but it doesn't return anything:
list.filter{x => obj.physicalResources.contains(x)}
Does anyone know how can I do this?
I can't reproduce your issue using filter:
val resources: List[String] =
("PR1" :: "PR2" :: "PR3" :: "PR4" :: Nil)
// Representing obj.physicalResources
val physicalResources: List[String] =
("PR1" :: "Something Else" :: "PR3" :: Nil)
val filtered: List[String] =
resources.filter{x => physicalResources.contains(x)}
println(filtered)
// Prints List(PR1, PR3)
But try this way that uses intersect:
// Take the intersection of the 2 lists; the parts that are the same
println(resources.intersect(physicalResources))
// Prints List(PR1, PR3)
Rolling your own method to accomplish this seems a little excessive.
I recently came up with a generic solution for a similar problem:
def hasSubsequence[A](sup: List[A], sub: List[A]): Boolean = {
def hasSubsequenceR[A](sup1: List[A], sub1: List[A]): Boolean = sup1 match {
case x :: xs => sub1 match {
case y :: ys if x == y => hasSubsequenceR(xs, ys)
case Nil => true
case _ => hasSubsequenceR(xs, sub)
}
case _ => false
}
hasSubsequenceR(sup, sub)
}
where sup is your list and sub is your obj.pr
Hope this helps
If I understand your question correctly, you're trying to match obj's PhysicalResource ids against the master list. List of PhysicalResource ids in obj is obj.pr.map(_.id), hence you can use intersect between the two lists to get the matching ids as follows:
case class PhysicalResource(id: String)
case class Task(id: String, pr: List[PhysicalResource])
val list: List[String] = "PR1" :: "PR2" :: "PR3" :: "PR4" :: Nil
val obj: Task = Task("T1", List(PhysicalResource("PR1"), PhysicalResource("PR3")))
list.intersect(obj.pr.map(_.id))
res1: List[String] = List(PR1, PR3)

How to use HList to validate input?

I'm using Shapeless 2.0 and I'm trying to use HList to validate input — with as much of the checking as possible performed at compile time.
I have an HList spec that specifies what type of input I'm expecting (the types should be checked at compile time) and may also include a runtime check to be performed (e.g., to test if a number is even or odd).
Consider the following specification:
trait Pred[T] { def apply(t: T): Boolean }
val IsString = new Pred[String] { def apply(s: String) = true }
val IsOddNumber = new Pred[Int] { def apply(n: Int) = n % 2 != 0 }
val IsEvenNumber = new Pred[Int] { def apply(n: Int) = n % 2 == 0 }
val spec = IsEvenNumber :: IsString :: IsString :: IsOddNumber :: HNil
And various sample inputs:
val goodInput = 4 :: "foo" :: "" :: 5 :: HNil
val badInput = 4 :: "foo" :: "" :: 4 :: HNil
val malformedInput = 4 :: 5 :: "" :: 6 :: HNil
How would I make a function where I can effectively do:
input.zip(spec).forall{case (input, test) => test(input)}
So the following would happen:
f(spec, goodInput) // true
f(spec, badInput) // false
f(spec, malformedInput) // Does not compile
These answers by Travis Brown include most of what's needed:
https://stackoverflow.com/a/20452151/86485
https://stackoverflow.com/a/21005225/86485
but it took me a long time to find those answers, figure out that they were applicable to your problem, and work out the details of combining and applying them.
And I think your question adds value because it demonstrates how this can come up when solving a practical problem, namely validating input. I'll also try to add value below by showing a complete solution including demo code and tests.
Here's generic code for doing the checking:
object Checker {
import shapeless._, poly._, ops.hlist._
object check extends Poly1 {
implicit def apply[T] = at[(T, Pred[T])]{
case (t, pred) => pred(t)
}
}
def apply[L1 <: HList, L2 <: HList, N <: Nat, Z <: HList, M <: HList](input: L1, spec: L2)(
implicit zipper: Zip.Aux[L1 :: L2 :: HNil, Z],
mapper: Mapper.Aux[check.type, Z, M],
length1: Length.Aux[L1, N],
length2: Length.Aux[L2, N],
toList: ToList[M, Boolean]) =
input.zip(spec)
.map(check)
.toList
.forall(Predef.identity)
}
And here's the demo usage code:
object Frank {
import shapeless._, nat._
def main(args: Array[String]) {
val IsString = new Pred[String] { def apply(s: String) = true }
val IsOddNumber = new Pred[Int] { def apply(n: Int) = n % 2 != 0 }
val IsEvenNumber = new Pred[Int] { def apply(n: Int) = n % 2 == 0 }
val spec = IsEvenNumber :: IsString :: IsString :: IsOddNumber :: HNil
val goodInput = 4 :: "foo" :: "" :: 5 :: HNil
val badInput = 4 :: "foo" :: "" :: 4 :: HNil
val malformedInput1 = 4 :: 5 :: "" :: 6 :: HNil
val malformedInput2 = 4 :: "foo" :: "" :: HNil
val malformedInput3 = 4 :: "foo" :: "" :: 5 :: 6 :: HNil
println(Checker(goodInput, spec))
println(Checker(badInput, spec))
import shapeless.test.illTyped
illTyped("Checker(malformedInput1, spec)")
illTyped("Checker(malformedInput2, spec)")
illTyped("Checker(malformedInput3, spec)")
}
}
/*
results when run:
[info] Running Frank
true
false
*/
Note the use of illTyped to verify that code that should not compile, does not.
Some side notes:
I initially went down a long garden path with this, where I thought it would be important for the polymorphic function check to have a more specific type than Poly1, to represent that the return type in all cases is Boolean. So I kept trying to make it work with extends (Id ~>> Boolean). But it turns out not to matter whether the type system knows that the result type is the Boolean in every case. It's enough that the only case that we actually have has the right type. extends Poly1 is a marvelous thing.
Value-level zip traditionally allows unequal lengths and discards the extras. Miles followed suit in Shapeless's type-level zip, so we need a separate check for equal lengths.
It's a bit sad that the call site has to import nat._, otherwise the implicit instances for Length aren't found. One would prefer these details to be handled at the definition site. (A fix is pending.)
If I understand correctly, I can't use Mapped (a la https://stackoverflow.com/a/21005225/86485) to avoid the length check, because some of my checkers (e.g. IsString) have singleton types that are more specific than just e.g. Pred[String].
Travis points out that Pred could extend T => Boolean, making it possible to use ZipApply. I leave following this suggestion as an exercise for the reader :-)

Filter heterogeneous list for type

I've an initial list that consists in different types of elements and I've to filter it to just take the int and double values.
For example (1 :: "hello" :: 100 :: 3.14 :: ('a'::10::Nil) :: 'c' :: (5,7,'a') :: Nil) should become (1, 100, 3.14, List(10), (5,7))
I'm having trouble coming up with a solution because once the list is passed to a method it becomes a List[Any] type of list and I need to know the type of each element before casting it. It wouldn't be a problem it didn't contain others substructures such as tuples as I could manage something with a pattern matching.
Is it possible somehow to get the specific type of a Any element and to cast it?
As an academic exercise it's rather silly. You should be learning how to avoid situations like this instead of trying to deal with it. Still, bad code can be rather instructive at times.
def intOrDbl(la :List[Any]) :List[Any] = la.flatMap{
case i:Int => List(i)
case d:Double => List(d)
case l:List[_] => List(intOrDbl(l))
case t:Product => val res = intOrDbl(t.productIterator.toList)
res.length match {
case 0 => Nil
case 1 => List(res)
case 2 => List((res(0),res(1)))
case 3 => List((res(0),res(1),res(2)))
case 4 => List((res(0),res(1),res(2),res(3)))
// etc.
}
case _ => Nil
}
val data = 1 :: "hello" :: 100 :: 3.14 :: ('a'::10::Nil) :: 'c' :: (5,7,'a') :: Nil
intOrDbl(data)
//res0: List[Any] = List(1, 100, 3.14, List(10), (5,7))
One choice you have is to put your result type into an ADT. Here is how it might work:
sealed trait IntOrDoubleOrList
case class IntValue(value: Int) extends IntOrDoubleOrList
case class DoubleValue(value: Double) extends IntOrDoubleOrList
case class ListValue(value: List[IntOrDoubleOrList]) extends IntOrDoubleOrList
def filterIntOrDouble(l: List[_]): List[IntOrDoubleOrList] = {
l.collect({
case iv: Int => IntValue(iv)
case dv: Double => DoubleValue(dv)
case lv: List[_] => ListValue(filterIntOrDouble(lv))
})
}
def test(): Unit = {
val origList = (1 :: "hello" :: 100 :: 3.14 :: ('a' :: 10 :: Nil) :: 'c' :: (5, 7, 'a') :: Nil)
val f = filterIntOrDouble(origList)
println(f)
}
Depending on you further needs you may extend the IntOrDoubleOrList trait with some helper methods like foreach(intHandler: Int => Unit, doubleHandler: Double => Unit)