project/BufferableGenerator.scala (50 lines of code) (raw):

package bijection object BufferableGenerator { val pkg = "package com.twitter.bijection" /* Example of the code generated: implicit def tuple2[A,B](implicit ba: Bufferable[A], bb: Bufferable[B]): Bufferable[(A,B)] = new AbstractBufferable[(A,B)] { def put(bytebuf: ByteBuffer, tup: (A,B)) = { var nextBb = bytebuf nextBb = reallocatingPut(nextBb) { ba.put(_, tup._1) } nextBb = reallocatingPut(nextBb) { bb.put(_, tup._2) } nextBb } // this should perform better than for comprehension def get(bytebuf: ByteBuffer) = attempt(bytebuf) { bytebuf => val (bufa, a) = ba.unsafeGet(bytebuf) val (bufb, b) = bb.unsafeGet(bufa) (bufb, (a,b)) } } */ val lowerLetters = ('a' to 'z').toIndexedSeq val upperLetters = ('A' to 'Z').toIndexedSeq def bufferableParam(idx: Int) = "b" + lowerLetters(idx) + ": Bufferable[" + upperLetters(idx) + "]" def typeList(cnt: Int) = upperLetters.slice(0, cnt) map { _.toString } mkString (",") def tupleTypeList(cnt: Int) = "Tuple" + cnt + "[" + typeList(cnt) + "]" def reallocatingPut(idx: Int) = "nextBb = reallocatingPut(nextBb) { b" + lowerLetters(idx) + ".put(_, tup._" + (idx + 1) + ") }" def bufferGet(idx: Int) = { val getFrom = if (idx == 0) "bytebuf" else ("buf" + lowerLetters(idx - 1)) val lowlet = lowerLetters(idx) "val (buf%s, %s) = b%s.unsafeGet(%s)".format(lowlet, lowlet, lowlet, getFrom) } def bufferableType(idx: Int) = "Bufferable[" + upperLetters(idx) + "]" // Here we put it all together: def implicitTuple(cnt: Int): String = " implicit def tuple" + cnt + "[" + typeList(cnt) + "](implicit " + ((0 until cnt) map { bufferableParam(_) } mkString (", ")) + "):\n" + " Bufferable[" + tupleTypeList(cnt) + "] = new AbstractBufferable[" + tupleTypeList( cnt ) + "] {\n" + " def put(bytebuf: ByteBuffer, tup: " + tupleTypeList(cnt) + ") = {\n" + " var nextBb = bytebuf\n" + " " + ((0 until cnt) map { reallocatingPut(_) }).mkString("", "\n ", "\n") + " nextBb\n" + " }\n" + " def get(bytebuf: ByteBuffer) = attempt(bytebuf) { bytebuf =>\n" + " " + ((0 until cnt) map { bufferGet(_) }).mkString("", "\n ", "\n") + " val res = Tuple" + cnt + (0 until cnt) .map { lowerLetters(_) } .mkString("(", ", ", ")") + "\n" + " (buf" + lowerLetters(cnt - 1) + ", res)\n" + " }\n" + " }" def generate = { val b = new StringBuffer b.append("// Autogenerated code DO NOT EDIT BY HAND\n") b.append(pkg).append("\n") b.append("import Bufferable.reallocatingPut\n") b.append("import java.nio.ByteBuffer\n") b.append("import com.twitter.bijection.Inversion.attempt\n") b.append("\ntrait GeneratedTupleBufferable {\n") (1 to 22).foreach { cnt => b.append(implicitTuple(cnt)).append("\n") } b.append("}") b.toString } }