public static NestedText GenSerializer(Arr <Arg> args, Option <int> typeNumber, string funcName) { Text GenSerializer(TgType type) => type.Match( primitive: x => $"Write{x.Type}", typeRef: x => "WriteSerializable", vector: x => Concat( $"WriteVector<{TgTypeConverter.ConvertType(x.Type)}>(", GenSerializer(x.Type), ")" ) ); Option <Text> GenNonFlagArgSerializer(Arg arg) => arg.Kind.Match( _: () => throw new Exception("WTF"), required: _ => GenSerializer(arg.Type).Apply(Some), optional: x => arg.Type == TgType.OfPrimitive(PrimitiveType.True) ? None : Concat( $"WriteOption<{TgTypeConverter.ConvertType(arg.Type)}>(", GenSerializer(arg.Type), ")" ).Apply(Some) ).Map(s => Concat($"Write({arg.Name}, bw, ", s, ");") ); Text GenMaskSerializer(IEnumerable <(string, int)> maskArgs) => maskArgs.ToArr() .Apply(Optional).Filter(xs => xs.Count > 0) .Map(xs => xs .Map(x => $"MaskBit({x.Item2}, {x.Item1})").Map(String).Reduce((x, y) => Concat(x, " | ", y)) ) .IfNone("0") .Apply(mask => Concat("Write(", mask, ", bw, WriteInt);")); Option <Text> GenArgSerializer(Arg arg) => arg.Kind.Match( _: () => GenNonFlagArgSerializer(arg), flags: _ => args.Choose(x => x.Kind.Match( _: () => None, optional: optional => ($"{x.Name}", optional.Flag.Bit).Apply(Some) )).Apply(GenMaskSerializer) ); var body = args.Choose(GenArgSerializer).Map(Line).Scope().Apply(s => typeNumber .Map(Helpers.TypeNumber).Map(x => Line($"WriteUint(bw, {x});")).Map(typeNumSer => Scope(typeNumSer, s)) .IfNone(s) ); var def = Scope( Line($"void {funcName}(BinaryWriter bw)"), Line("{"), Indent(1, body), Line("}") ); return(def); }