or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

builtin-types.mdcore-serialization.mdindex.mdjson-integration.mdmessagepack-integration.mdsealed-traits.mdstreaming.mdtype-classes.md
tile.json

type-classes.mddocs/

Type Classes

Reader, Writer, and ReadWriter type classes define serialization behavior for types in uPickle. These are the core abstractions that enable automatic and custom serialization.

Capabilities

Reader Type Class

Represents the ability to read (deserialize) a value of type T from structured data.

/**
 * Represents the ability to read a value of type T
 * Extends Visitor for processing structured data traversal
 */
trait Reader[T] extends upickle.core.Visitor[Any, T] {
  def map[Z](f: T => Z): Reader[Z]
  def mapNulls[Z](f: T => Z): Reader[Z]
  def narrow[K <: T]: Reader[K]
}

Usage Examples:

import upickle.default._
import upickle.core._

// Custom reader for a simple case
implicit val customIntReader: Reader[Int] = new SimpleReader[Int] {
  override def expectedMsg = "expected integer"
  override def visitInt32(d: Int, index: Int) = d
  override def visitString(s: CharSequence, index: Int) = s.toString.toInt
}

// Transform existing reader
val positiveIntReader = IntReader.map(math.abs)

// Use reader directly
val result = customIntReader.transform(ujson.parse("42"))

Writer Type Class

Represents the ability to write (serialize) a value of type T to structured data.

/**
 * Represents the ability to write a value of type T
 * Extends Transformer for converting values to structured data
 */
trait Writer[T] extends Transformer[T] {
  def isJsonDictKey: Boolean
  def narrow[K]: Writer[K]
  def write0[V](out: Visitor[_, V], v: T): V
  def write[V](out: Visitor[_, V], v: T): V
  def comap[U](f: U => T): Writer[U]
  def comapNulls[U](f: U => T): Writer[U]
}

Usage Examples:

import upickle.default._
import upickle.core._

// Custom writer for a simple case
implicit val customIntWriter: Writer[Int] = new Writer[Int] {
  override def isJsonDictKey = true
  def write0[V](out: Visitor[_, V], v: Int): V = {
    out.visitString(s"number_$v", -1)
  }
}

// Transform existing writer
case class UserId(id: Int)
implicit val userIdWriter: Writer[UserId] = IntWriter.comap(_.id)

// Use writer directly  
val json = customIntWriter.transform(42, ujson.StringRenderer()).toString

ReadWriter Type Class

Combined Reader and Writer with additional utilities for bidirectional serialization.

/**
 * A combined Reader and Writer, along with some utility methods
 */
trait ReadWriter[T] extends Reader[T] with Writer[T] {
  override def narrow[K]: ReadWriter[K]
  def bimap[V](f: V => T, g: T => V): ReadWriter[V]
}

Usage Examples:

import upickle.default._

// Custom ReadWriter
case class Temperature(celsius: Double)

implicit val temperatureRW: ReadWriter[Temperature] = 
  readwriter[Double].bimap(Temperature(_), _.celsius)

// Use bidirectionally
val temp = Temperature(25.0)
val json = write(temp)  // Uses Writer part
val parsed = read[Temperature](json)  // Uses Reader part

Reader Companion Object

Utilities for creating and combining Reader instances.

object Reader {
  /**
   * Merges multiple tagged readers for sealed trait handling
   */
  def merge[T](tagKey: String, readers: Reader[_ <: T]*): TaggedReader.Node[T]
  def merge[T](readers: Reader[_ <: T]*): TaggedReader.Node[T]
  
  /**
   * Delegates reader functionality to another visitor
   */
  class Delegate[T, V](delegatedReader: Visitor[T, V]) extends Reader[V]
  
  /**
   * Maps reader output through a transformation function
   */
  abstract class MapReader[-T, V, Z](delegatedReader: Visitor[T, V]) extends Reader[Z]
}

Usage Examples:

import upickle.default._
import upickle.core._

// Merge readers for sealed trait
sealed trait Animal
case class Dog(name: String) extends Animal  
case class Cat(name: String) extends Animal

val animalReader = Reader.merge[Animal](
  reader[Dog], reader[Cat]
)

Writer Companion Object

Utilities for creating and combining Writer instances.

object Writer {
  /**
   * Merges multiple tagged writers for sealed trait handling
   */
  def merge[T](writers: Writer[_ <: T]*): TaggedWriter.Node[T]
  
  /**
   * Maps writer input through a transformation function
   */
  class MapWriter[U, T](src: Writer[T], f: U => T) extends Writer[U]
  
  /**
   * Maps writer input with null handling
   */
  class MapWriterNulls[U, T](src: Writer[T], f: U => T) extends Writer[U]
}

ReadWriter Companion Object

Utilities for creating and combining ReadWriter instances.

object ReadWriter {
  /**
   * Merges multiple tagged readwriters for sealed trait handling
   */
  def merge[T](tagKey: String, rws: ReadWriter[_ <: T]*): TaggedReadWriter[T]
  def merge[T](rws: ReadWriter[_ <: T]*): TaggedReadWriter[T]
  
  /**
   * Joins separate Reader and Writer into ReadWriter
   */
  implicit def join[T](implicit r0: Reader[T], w0: Writer[T]): ReadWriter[T]
  
  /**
   * Delegates readwriter functionality
   */
  abstract class Delegate[T](other: Visitor[Any, T]) extends ReadWriter[T]
}

Usage Examples:

import upickle.default._

// Join separate instances
implicit val stringReader: Reader[String] = StringReader
implicit val stringWriter: Writer[String] = StringWriter
implicit val stringRW: ReadWriter[String] = ReadWriter.join[String]

// Merge for sealed traits
sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(width: Double, height: Double) extends Shape

implicit val shapeRW = ReadWriter.merge[Shape](
  readwriter[Circle], readwriter[Rectangle]
)

Key Utilities

Functions for marking types as suitable for JSON dictionary keys.

/**
 * Mark a ReadWriter[T] as something that can be used as a key in a JSON dictionary
 */
def stringKeyRW[T](readwriter: ReadWriter[T]): ReadWriter[T]

/**
 * Mark a Writer[T] as something that can be used as a key in a JSON dictionary  
 */
def stringKeyW[T](readwriter: Writer[T]): Writer[T]

Usage Examples:

import upickle.default._

// Custom ID type that can be used as map key
case class ProductId(id: String)

implicit val productIdRW: ReadWriter[ProductId] = 
  stringKeyRW(readwriter[String].bimap(ProductId(_), _.id))

// Now can serialize Map[ProductId, Product]
val productMap: Map[ProductId, Product] = Map(
  ProductId("abc") -> Product("Widget", 10.0)
)

val json = write(productMap)
// Result: {"abc": {"name": "Widget", "price": 10.0}}

Types

trait SimpleReader[T] extends Reader[T] with upickle.core.SimpleVisitor[Any, T]

trait ObjectWriter[T] extends Writer[T] {
  def length(v: T): Int  
  def writeToObject[R](ctx: ObjVisitor[_, R], v: T): Unit
}

/**
 * Implicit to indicate that we are currently deriving an implicit T
 * Used to avoid infinite recursion in implicit derivation
 */
class CurrentlyDeriving[T]