def join[T]()

in protobuf/src/main/scala/magnolify/protobuf/ProtobufType.scala [98:183]


  def join[T](caseClass: CaseClass[Typeclass, T]): ProtobufField[T] = {
    if (caseClass.isValueClass) {
      val p = caseClass.parameters.head
      val tc = p.typeclass
      new ProtobufField[T] {
        override type FromT = tc.FromT
        override type ToT = tc.ToT

        override val default: Option[T] = tc.default.map(x => caseClass.construct(_ => x))
        override def from(v: FromT)(cm: CaseMapper): T = caseClass.construct(_ => tc.from(v)(cm))
        override def to(v: T, b: Message.Builder)(cm: CaseMapper): ToT =
          tc.to(p.dereference(v), b)(cm)
      }

    } else {
      new Record[T] {
        // One Record[T] instance may be used for multiple Message types
        @transient private lazy val fieldsCache: concurrent.Map[String, Array[FieldDescriptor]] =
          concurrent.TrieMap.empty

        private def getFields(descriptor: Descriptor)(cm: CaseMapper): Array[FieldDescriptor] =
          fieldsCache.getOrElseUpdate(
            descriptor.getFullName, {
              val fields = new Array[FieldDescriptor](caseClass.parameters.size)
              caseClass.parameters.foreach(p =>
                fields(p.index) = descriptor.findFieldByName(cm.map(p.label))
              )
              fields
            }
          )

        private def newFieldBuilder(b: Message.Builder)(f: FieldDescriptor): Message.Builder =
          if (f.getType != FieldDescriptor.Type.MESSAGE) null
          else b.newBuilderForField(f)

        override def checkDefaults(descriptor: Descriptor)(cm: CaseMapper): Unit = {
          val fields = getFields(descriptor)(cm)
          caseClass.parameters.foreach { p =>
            val field = fields(p.index)
            val protoDefault = if (field.hasDefaultValue) {
              Some(p.typeclass.fromAny(field.getDefaultValue)(cm))
            } else {
              p.typeclass.default
            }
            p.default.foreach { d =>
              require(
                protoDefault.contains(d),
                s"Default mismatch ${caseClass.typeName.full}#${p.label}: $d != ${protoDefault.orNull}"
              )
            }
            if (field.getType == FieldDescriptor.Type.MESSAGE) {
              p.typeclass.checkDefaults(field.getMessageType)(cm)
            }
          }
        }

        override def from(v: Message)(cm: CaseMapper): T = {
          val descriptor = v.getDescriptorForType
          val fields = getFields(descriptor)(cm)

          caseClass.construct { p =>
            val field = fields(p.index)
            // check hasPresence to make sure hasField is meaningful
            val value = if (field.hasPresence && !v.hasField(field)) {
              null
            } else {
              v.getField(field)
            }
            p.typeclass.fromAny(value)(cm)
          }
        }

        override def to(v: T, bu: Message.Builder)(cm: CaseMapper): Message = {
          val fields = getFields(bu.getDescriptorForType)(cm)
          caseClass.parameters
            .foldLeft(bu) { (b, p) =>
              val field = fields(p.index)
              val builder = newFieldBuilder(bu)(field)
              val value = p.typeclass.to(p.dereference(v), builder)(cm)
              if (value == null) b else b.setField(field, value)
            }
            .build()
        }
      }
    }
  }