Created
June 11, 2013 20:09
-
-
Save heathermiller/5760171 to your computer and use it in GitHub Desktop.
A sample simplified edn PickleFormat for Scala Pickling. That's right, transfer data to a Clojure app! (Edn stands for "extensible data notation" and is Clojure's data transfer format.)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.pickling._ | |
import scala.reflect.runtime.universe._ | |
import scala.util.parsing.json._ | |
import scala.collection.mutable.{StringBuilder, Stack} | |
package object edn { | |
implicit val pickleFormat: EdnPickleFormat = new EdnPickleFormat | |
} | |
package edn { | |
case class EdnPickle(value: String) extends Pickle { | |
type ValueType = String | |
type PickleFormatType = EdnPickleFormat | |
} | |
class EdnPickleFormat extends PickleFormat { | |
type PickleType = EdnPickle | |
def createBuilder() = new EdnPickleBuilder(this) | |
def createReader(pickle: EdnPickle, mirror: Mirror) = ??? | |
} | |
class EdnPickleBuilder(format: EdnPickleFormat) extends PBuilder with PickleTools { | |
private val buf = new StringBuilder() | |
private val tags = new Stack[FastTypeTag[_]]() | |
private def append(s: String) = buf ++= s | |
private def pickleArray(arr: Array[_], tag: FastTypeTag[_]) = { | |
append("[") | |
hintStaticallyElidedType() | |
hintTag(tag) | |
pinHints() | |
var i = 0 | |
while (i < arr.length) { | |
putElement(b => b.beginEntry(arr(i)).endEntry()) | |
i += 1 | |
} | |
unpinHints() | |
append("]") | |
} | |
private val primitives = Map[String, Any => Unit]( | |
FastTypeTag.Null.key -> ((picklee: Any) => append("null")), | |
FastTypeTag.Int.key -> ((picklee: Any) => append(picklee.toString)), | |
FastTypeTag.Long.key -> ((picklee: Any) => append("\"" + JSONFormat.quoteString(picklee.toString) + "\"")), | |
FastTypeTag.Short.key -> ((picklee: Any) => append(picklee.toString)), | |
FastTypeTag.Double.key -> ((picklee: Any) => append(picklee.toString)), | |
FastTypeTag.Float.key -> ((picklee: Any) => append(picklee.toString)), | |
FastTypeTag.Boolean.key -> ((picklee: Any) => append(picklee.toString)), | |
FastTypeTag.Byte.key -> ((picklee: Any) => append(picklee.toString)), | |
FastTypeTag.Char.key -> ((picklee: Any) => append("\"" + JSONFormat.quoteString(picklee.toString) + "\"")), | |
FastTypeTag.ScalaString.key -> ((picklee: Any) => append("\"" + JSONFormat.quoteString(picklee.toString) + "\"")), | |
FastTypeTag.JavaString.key -> ((picklee: Any) => append("\"" + JSONFormat.quoteString(picklee.toString) + "\"")), | |
FastTypeTag.ArrayInt.key -> ((picklee: Any) => pickleArray(picklee.asInstanceOf[Array[Int]], FastTypeTag.Int)) | |
) | |
def beginEntry(picklee: Any): this.type = withHints { hints => | |
tags.push(hints.tag) | |
if (primitives.contains(hints.tag.key)) { | |
if (hints.isElidedType) primitives(hints.tag.key)(picklee) | |
else ??? | |
} else append("#pickling/" + typeToString(hints.tag.tpe) + " {") | |
this | |
} | |
def putField(name: String, pickler: this.type => Unit): this.type = { | |
append(" :" + name + " ") | |
pickler(this) | |
this | |
} | |
def endEntry(): Unit = { | |
if (primitives.contains(tags.pop().key)) {} // do nothing | |
else append(" }") | |
} | |
def beginCollection(length: Int): this.type = { | |
putField("elems", b => ()) | |
append("[") | |
this | |
} | |
def putElement(pickler: this.type => Unit): this.type = { | |
if (buf.toString.trim.last != '[') append(", ") | |
pickler(this) | |
this | |
} | |
def endCollection(l: Int): Unit = append("]") | |
def result(): EdnPickle = EdnPickle(buf.toString) | |
} | |
} |
Nice! Here's a hand-rolled scala edn reader/writer -- slightly more complete but still tiny.
https://github.com/martintrojer/edn-scala
I'd be interested to convert this into a proper 'pickling target' if you'd like.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note that we only provide the
PickleBuilder
in this gist-- if a Scala app was to receive anEdnPickle
, we'd need to implement aPickleReader
in order to effectively read and deserialize it.