Code generator reference
We support the following concepts:
- Enumerations
 - Algebraic Data Types
 - Type aliases
 - Mixins
 - Data Classes
 - Identifiers
 - Services
 
Inheritance
- We support two forms of inheritance: interface inheritance (
&modifier) and structural mixins (*modifier) - The only difference between structural inheritance and interface inheritance is presence/absence of the base interface in the list of supertypes
 - Both Data Classes and Mixins support both forms of inheritance
 - Services, ADTs, Type Aliases, Identifiers and Enumerations does not support inheritance
 - We provide widening narrowing implicit functions as well as copy constructors for all the generated entities
 
Example
mixin IntPair {
  x: i32
  y: i32
}
mixin Metadata {
  id: str
  name: str
}
mixin PointLike {
  + Metadata
  * IntPair
}
data Point {
  + Metadata
  * IntPair
}
Scala output
trait IntPair {
  def y: Int
  def x: Int
}
trait Metadata {
  def name: String
  def id: String
}
final case class Point(y: Int, name: String, x: Int, id: String) extends Metadata
trait PointLike extends Metadata {
  def y: Int
  def x: Int
  def name: String
  def id: String
}
Constructs
Notes:
- All the examples of generated code are given in minimal form
 - Generated code for codecs, implicit conversions and type info is omitted
 
mixin: Mixin
 mixin Person {
   name: str
   surname: str
 }
Scala output
trait Person {
  def name: String
  def surname: String
}
data: Data Class
Differences between Mixins and Data Classes:
- Data classes cannot be subclassed
 - Data classes are always rendered as case classes, Mixins are always rendered as pair of Interface and Implementation
 
 data HumanUser {
   + IdentifiedUser
   * Person
 }
Scala output
final case class HumanUser(name: String, surname: String, id: UserId) extends IdentifiedUser with Person
adt: Algebraic Data Type
 mixin Success {
   values: map[str, str]
 }
 mixin Failure {
   message: str
 }
 adt Result {
   Success
   Failure
 }
Scala output
trait Failure extends Any { def message: String }
trait Success extends Any { def values: scala.collection.immutable.Map[String, String] }
sealed trait Result
object Result {
  type Element = Result
  case class Success(value: Success) extends Result
  case class Failure(value: Failure) extends Result
}
alias: Type Alias
alias UserId = str
Scala output
package object domain01 {
type UserId = String
}
enum: Enumeration
enum Gender {
  MALE
  FEMALE
}
Scala output
sealed trait Gender
object Gender {
  type Element = Gender
  def all: Seq[Gender] = Seq(MALE, FEMALE)
  def parse(value: String) = value match {
    case "MALE" => MALE
    case "FEMALE" => FEMALE
  }
  case object MALE extends Gender { override def toString: String = "MALE" }
  case object FEMALE extends Gender { override def toString: String = "FEMALE" }
}
id: Identifier
Notes:
- You can use only scalar builtin types for identifier fields
 - We provide both parser and sane 
.toStringimplementation .toStringuses the following format:Name#urlencoded(part1):urlencoded(part2):...- Fields are sorted by name before using in parser and 
.toString 
id UserId {
  value: uid
  company: uid
}
Scala output
final case class UserId(value: java.util.UUID, company: java.util.UUID) {
  override def toString: String = {
    import izumi.idealingua.runtime.model.IDLIdentifier._
    val suffix = Seq(this.company, this.value).map(part => escape(part.toString)).mkString(":")
    s"UserId#$suffix"
  }
}
object UserId {
  def parse(s: String): UserId = {
    import izumi.idealingua.runtime.model.IDLIdentifier._
    val withoutPrefix = s.substring(s.indexOf("#") + 1)
    val parts = withoutPrefix.split(":").map(part => unescape(part))
    UserId(parsePart[java.util.UUID](parts(0), classOf[java.util.UUID]), parsePart[java.util.UUID](parts(1), classOf[java.util.UUID]))
  }
}
service: Service
id RecordId {
  value: uid
}
mixin WithRecordId {
  id: RecordId
}
mixin WithResult {
  result: shared.rpc#Result
}
mixin UserData {
  email: str
}
mixin PrivateUserData {
  balance: f64
}
service UserService {
  def deleteUser(WithRecordId): (WithResult)
  def createUser(UserData, PrivateUserData): (WithRecordId, WithResult)
}
Notes:
- Service signature cannot accept anything except of Mixins (improvements planned)
 ServerDispatcherallows you to route wrapped result type to an appropriate method of an abstract implementationClientDispatcherjust passes input to an abstract receiverClientWrapperallows you to transform unwrapped method signatures into wrapping instancesServerWrappedprovides you an unwrapping service implementationServiceUnwrappedprovides you a way to implement services with signatures unwrapped
Scala output
import _root_.izumi.idealingua.model._
import _root_.izumi.idealingua.runtime._
class UserServiceServerDispatcher[R[+_], S <: UserService[R]](val service: S) extends transport.AbstractServerDispatcher[R, S] {
  import UserService._
  override def dispatch(input: UserService.InUserService): R[UserService.OutUserService] = input match {
    case value: UserService.InDeleteUser =>
      service.deleteUser(value)
    case value: UserService.InCreateUser =>
      service.createUser(value)
  }
}
class UserServiceClientDispatcher[R[+_], S <: UserService[R]](dispatcher: transport.AbstractClientDispatcher[R, S]) extends UserService[R] {
  import UserService._
  def deleteUser(input: UserService.InDeleteUser): Result[UserService.OutDeleteUser] = dispatcher.dispatch(input, classOf[UserService.OutDeleteUser])
  def createUser(input: UserService.InCreateUser): Result[UserService.OutCreateUser] = dispatcher.dispatch(input, classOf[UserService.OutCreateUser])
}
class UserServiceClientWrapper[R[+_], S <: UserService[R]](val service: S) extends model.IDLClientWrapper[R, S] {
  import UserService._
  def deleteUser(id: RecordId): Result[UserService.OutDeleteUser] = {
    service.deleteUser(UserService.InDeleteUser(id = id))
  }
  def createUser(balance: Double, email: String): Result[UserService.OutCreateUser] = {
    service.createUser(UserService.InCreateUser(balance = balance, email = email))
  }
}
trait UserServiceUnwrapped[R[+_], S <: UserService[R]] extends model.IDLServiceExploded[R, S] {
  import UserService._
  def deleteUser(id: RecordId): Result[UserService.OutDeleteUser]
  def createUser(balance: Double, email: String): Result[UserService.OutCreateUser]
}
class UserServiceServerWrapper[R[+_], S <: UserService[R]](val service: UserServiceUnwrapped[R, S]) extends UserService[R] {
  import UserService._
  def deleteUser(input: UserService.InDeleteUser): Result[UserService.OutDeleteUser] = service.deleteUser(id = input.id)
  def createUser(input: UserService.InCreateUser): Result[UserService.OutCreateUser] = service.createUser(balance = input.balance, email = input.email)
}
trait UserService[R[_]] extends izumi.idealingua.runtime.model.IDLService[R] {
  import UserService._
  override type InputType = UserService.InUserService
  override type OutputType = UserService.OutUserService
  override def inputClass: Class[UserService.InUserService] = classOf[UserService.InUserService]
  override def outputClass: Class[UserService.OutUserService] = classOf[UserService.OutUserService]
  def deleteUser(input: UserService.InDeleteUser): Result[UserService.OutDeleteUser]
  def createUser(input: UserService.InCreateUser): Result[UserService.OutCreateUser]
}
object UserService {
  sealed trait InUserService extends Any
  sealed trait OutUserService extends Any
  case class InDeleteUser(id: RecordId) extends UserService.InUserService with WithRecordId
  case class OutDeleteUser(result: shared.rpc.Result) extends AnyVal with UserService.OutUserService with WithResult
  case class InCreateUser(balance: Double, email: String) extends UserService.InUserService with UserData with PrivateUserData
  case class OutCreateUser(result: shared.rpc.Result, id: RecordId) extends UserService.OutUserService with WithRecordId with WithResult
}
1.2.20