1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "fidl/c_generator.h"
6
7#include "fidl/attributes.h"
8#include "fidl/names.h"
9
10namespace fidl {
11
12namespace {
13
14// RAII helper class to reset the iostream to its original flags.
15class IOFlagsGuard {
16public:
17    explicit IOFlagsGuard(std::ostream* stream)
18        : stream_(stream), flags_(stream_->flags()) {
19    }
20    ~IOFlagsGuard() {
21        stream_->setf(flags_);
22    }
23
24private:
25    std::ostream* stream_;
26    std::ios::fmtflags flags_;
27};
28
29// Various string values are looked up or computed in these
30// functions. Nothing else should be dealing in string literals, or
31// computing strings from these or AST values.
32
33constexpr const char* kIndent = "    ";
34
35CGenerator::Member MessageHeader() {
36    return {
37        flat::Type::Kind::kIdentifier,
38        flat::Decl::Kind::kStruct,
39        "fidl_message_header_t",
40        "hdr",
41        {},
42        {},
43        types::Nullability::kNonnullable,
44    };
45}
46
47// Functions named "Emit..." are called to actually emit to an std::ostream
48// is here. No other functions should directly emit to the streams.
49
50std::ostream& operator<<(std::ostream& stream, StringView view) {
51    stream.rdbuf()->sputn(view.data(), view.size());
52    return stream;
53}
54
55void EmitFileComment(std::ostream* file) {
56    *file << "// WARNING: This file is machine generated by fidlc.\n\n";
57}
58
59void EmitHeaderGuard(std::ostream* file) {
60    // TODO(704) Generate an appropriate header guard name.
61    *file << "#pragma once\n";
62}
63
64void EmitIncludeHeader(std::ostream* file, StringView header) {
65    *file << "#include " << header << "\n";
66}
67
68void EmitBeginExternC(std::ostream* file) {
69    *file << "#if defined(__cplusplus)\nextern \"C\" {\n#endif\n";
70}
71
72void EmitEndExternC(std::ostream* file) {
73    *file << "#if defined(__cplusplus)\n}\n#endif\n";
74}
75
76void EmitBlank(std::ostream* file) {
77    *file << "\n";
78}
79
80void EmitMemberDecl(std::ostream* file, const CGenerator::Member& member) {
81    *file << member.type << " " << member.name;
82    for (uint32_t array_count : member.array_counts) {
83        *file << "[" << array_count << "]";
84    }
85}
86
87void EmitMethodInParamDecl(std::ostream* file, const CGenerator::Member& member) {
88    switch (member.kind) {
89    case flat::Type::Kind::kArray:
90        *file << "const " << member.type << " " << member.name;
91        for (uint32_t array_count : member.array_counts) {
92            *file << "[" << array_count << "]";
93        }
94        break;
95    case flat::Type::Kind::kVector:
96        *file << "const " << member.element_type << "* " << member.name << "_data, "
97              << "size_t " << member.name << "_count";
98        break;
99    case flat::Type::Kind::kString:
100        *file << "const char* " << member.name << "_data, "
101              << "size_t " << member.name << "_size";
102        break;
103    case flat::Type::Kind::kHandle:
104    case flat::Type::Kind::kRequestHandle:
105    case flat::Type::Kind::kPrimitive:
106        *file << member.type << " " << member.name;
107        break;
108    case flat::Type::Kind::kIdentifier:
109        switch (member.decl_kind) {
110        case flat::Decl::Kind::kConst:
111            assert(false && "bad decl kind for member");
112            break;
113        case flat::Decl::Kind::kEnum:
114        case flat::Decl::Kind::kInterface:
115            *file << member.type << " " << member.name;
116            break;
117        case flat::Decl::Kind::kStruct:
118        case flat::Decl::Kind::kTable:
119        case flat::Decl::Kind::kUnion:
120            switch (member.nullability) {
121            case types::Nullability::kNullable:
122                *file << "const " << member.type << " " << member.name;
123                break;
124            case types::Nullability::kNonnullable:
125                *file << "const " << member.type << "* " << member.name;
126                break;
127            }
128            break;
129        }
130        break;
131    }
132}
133
134void EmitMethodOutParamDecl(std::ostream* file, const CGenerator::Member& member) {
135    switch (member.kind) {
136    case flat::Type::Kind::kArray:
137        *file << member.type << " out_" << member.name;
138        for (uint32_t array_count : member.array_counts) {
139            *file << "[" << array_count << "]";
140        }
141    case flat::Type::Kind::kVector:
142        *file << member.element_type << "* " << member.name << "_buffer, "
143              << "size_t " << member.name << "_capacity, "
144              << "size_t* out_" << member.name << "_count";
145        break;
146    case flat::Type::Kind::kString:
147        *file << "char* " << member.name << "_buffer, "
148              << "size_t " << member.name << "_capacity, "
149              << "size_t* out_" << member.name << "_size";
150        break;
151    case flat::Type::Kind::kHandle:
152    case flat::Type::Kind::kRequestHandle:
153    case flat::Type::Kind::kPrimitive:
154        *file << member.type << "* out_" << member.name;
155        break;
156    case flat::Type::Kind::kIdentifier:
157        switch (member.decl_kind) {
158        case flat::Decl::Kind::kConst:
159            assert(false && "bad decl kind for member");
160            break;
161        case flat::Decl::Kind::kEnum:
162        case flat::Decl::Kind::kInterface:
163            *file << member.type << "* out_" << member.name;
164            break;
165        case flat::Decl::Kind::kStruct:
166        case flat::Decl::Kind::kTable:
167        case flat::Decl::Kind::kUnion:
168            switch (member.nullability) {
169            case types::Nullability::kNullable:
170                *file << member.type << " out_" << member.name;
171                break;
172            case types::Nullability::kNonnullable:
173                *file << member.type << "* out_" << member.name;
174                break;
175            }
176            break;
177        }
178        break;
179    }
180}
181
182void EmitClientMethodDecl(std::ostream* file, StringView method_name,
183                          const std::vector<CGenerator::Member>& request,
184                          const std::vector<CGenerator::Member>& response) {
185    *file << "zx_status_t " << method_name << "(zx_handle_t _channel";
186    for (const auto& member : request) {
187        *file << ", ";
188        EmitMethodInParamDecl(file, member);
189    }
190    for (auto member : response) {
191        *file << ", ";
192        EmitMethodOutParamDecl(file, member);
193    }
194    *file << ")";
195}
196
197void EmitServerMethodDecl(std::ostream* file, StringView method_name,
198                          const std::vector<CGenerator::Member>& request,
199                          bool has_response) {
200    *file << "zx_status_t (*" << method_name << ")(void* ctx";
201    for (const auto& member : request) {
202        *file << ", ";
203        EmitMethodInParamDecl(file, member);
204    }
205    if (has_response) {
206        *file << ", fidl_txn_t* txn";
207    }
208    *file << ")";
209}
210
211void EmitServerDispatchDecl(std::ostream* file, StringView interface_name) {
212    *file << "zx_status_t " << interface_name
213          << "_dispatch(void* ctx, fidl_txn_t* txn, fidl_msg_t* msg, const "
214          << interface_name << "_ops_t* ops)";
215}
216
217void EmitServerTryDispatchDecl(std::ostream* file, StringView interface_name) {
218    *file << "zx_status_t " << interface_name
219          << "_try_dispatch(void* ctx, fidl_txn_t* txn, fidl_msg_t* msg, const "
220          << interface_name << "_ops_t* ops)";
221}
222
223void EmitServerReplyDecl(std::ostream* file, StringView method_name,
224                         const std::vector<CGenerator::Member>& response) {
225    *file << "zx_status_t " << method_name << "_reply(fidl_txn_t* _txn";
226    for (const auto& member : response) {
227        *file << ", ";
228        EmitMethodInParamDecl(file, member);
229    }
230    *file << ")";
231}
232
233bool IsStoredOutOfLine(const CGenerator::Member& member) {
234    if (member.kind == flat::Type::Kind::kVector ||
235        member.kind == flat::Type::Kind::kString)
236        return true;
237    if (member.kind == flat::Type::Kind::kIdentifier) {
238        return member.nullability == types::Nullability::kNullable &&
239               (member.decl_kind == flat::Decl::Kind::kStruct || member.decl_kind == flat::Decl::Kind::kUnion);
240    }
241    return false;
242}
243
244void EmitMeasureInParams(std::ostream* file,
245                         const std::vector<CGenerator::Member>& params) {
246    for (const auto& member : params) {
247        if (member.kind == flat::Type::Kind::kVector)
248            *file << " + FIDL_ALIGN(sizeof(*" << member.name << "_data) * " << member.name << "_count)";
249        else if (member.kind == flat::Type::Kind::kString)
250            *file << " + FIDL_ALIGN(" << member.name << "_size)";
251        else if (IsStoredOutOfLine(member))
252            *file << " + (" << member.name << " ? sizeof(*" << member.name << ") : 0u)";
253    }
254}
255
256void EmitMeasureOutParams(std::ostream* file,
257                          const std::vector<CGenerator::Member>& params) {
258    for (const auto& member : params) {
259        if (member.kind == flat::Type::Kind::kVector)
260            *file << " + FIDL_ALIGN(sizeof(*" << member.name << "_buffer) * " << member.name << "_capacity)";
261        else if (member.kind == flat::Type::Kind::kString)
262            *file << " + FIDL_ALIGN(" << member.name << "_capacity)";
263        else if (IsStoredOutOfLine(member))
264            *file << " + (out_" << member.name << " ? sizeof(*out_" << member.name << ") : 0u)";
265    }
266}
267
268// This function assumes the |params| are part of a [Layout="Simple"] interface.
269// In particular, simple interfaces don't have nullable structs or nested
270// vectors. The only secondary objects they contain are top-level vectors and
271// strings.
272size_t CountSecondaryObjects(const std::vector<CGenerator::Member>& params) {
273    size_t count = 0u;
274    for (const auto& member : params) {
275        if (IsStoredOutOfLine(member))
276            ++count;
277    }
278    return count;
279}
280
281void EmitLinearizeMessage(std::ostream* file,
282                          StringView receiver,
283                          StringView bytes,
284                          const std::vector<CGenerator::Member>& request) {
285    if (CountSecondaryObjects(request) > 0)
286        *file << kIndent << "uint32_t _next = sizeof(*" << receiver << ");\n";
287    for (const auto& member : request) {
288        const auto& name = member.name;
289        switch (member.kind) {
290        case flat::Type::Kind::kArray:
291            *file << kIndent << "memcpy(" << receiver << "->" << name << ", "
292                  << name << ", sizeof(" << receiver << "->" << name << "));\n";
293            break;
294        case flat::Type::Kind::kVector:
295            *file << kIndent << receiver << "->" << name << ".data = &" << bytes << "[_next];\n";
296            *file << kIndent << receiver << "->" << name << ".count = " << name << "_count;\n";
297            *file << kIndent << "memcpy(" << receiver << "->" << name << ".data, " << name << "_data, sizeof(*" << name << "_data) * " << name << "_count);\n";
298            *file << kIndent << "_next += FIDL_ALIGN(sizeof(*" << name << "_data) * " << name << "_count);\n";
299            break;
300        case flat::Type::Kind::kString:
301            *file << kIndent << receiver << "->" << name << ".data = &" << bytes << "[_next];\n";
302            *file << kIndent << receiver << "->" << name << ".size = " << name << "_size;\n";
303            *file << kIndent << "memcpy(" << receiver << "->" << name << ".data, " << name << "_data, " << name << "_size);\n";
304            *file << kIndent << "_next += FIDL_ALIGN(" << name << "_size);\n";
305            break;
306        case flat::Type::Kind::kHandle:
307        case flat::Type::Kind::kRequestHandle:
308        case flat::Type::Kind::kPrimitive:
309            *file << kIndent << receiver << "->" << name << " = " << name << ";\n";
310            break;
311        case flat::Type::Kind::kIdentifier:
312            switch (member.decl_kind) {
313            case flat::Decl::Kind::kConst:
314                assert(false && "bad decl kind for member");
315                break;
316            case flat::Decl::Kind::kEnum:
317            case flat::Decl::Kind::kInterface:
318                *file << kIndent << receiver << "->" << name << " = " << name << ";\n";
319                break;
320            case flat::Decl::Kind::kTable:
321                assert(false && "c-codegen for tables not yet implemented");
322                break;
323            case flat::Decl::Kind::kStruct:
324            case flat::Decl::Kind::kUnion:
325                switch (member.nullability) {
326                case types::Nullability::kNullable:
327                    *file << kIndent << "if (" << name << ") {\n";
328                    *file << kIndent << kIndent << receiver << "->" << name << " = (void*)&" << bytes << "[_next];\n";
329                    *file << kIndent << kIndent << "memcpy(" << receiver << "->" << name << ", " << name << ", sizeof(*" << name << "));\n";
330                    *file << kIndent << kIndent << "_next += sizeof(*" << name << ");\n";
331                    *file << kIndent << "} else {\n";
332                    *file << kIndent << kIndent << receiver << "->" << name << " = NULL;\n";
333                    *file << kIndent << "}\n";
334                    break;
335                case types::Nullability::kNonnullable:
336                    *file << kIndent << receiver << "->" << name << " = *" << name << ";\n";
337                    break;
338                }
339                break;
340            }
341        }
342    }
343}
344
345// Various computational helper routines.
346
347void EnumValue(types::PrimitiveSubtype type, const flat::Constant* constant,
348               const flat::Library* library, std::string* out_value) {
349    // TODO(kulakowski) Move this into library resolution.
350
351    std::ostringstream member_value;
352
353    switch (type) {
354    case types::PrimitiveSubtype::kInt8: {
355        int8_t value;
356        bool success = library->ParseIntegerConstant(constant, &value);
357        if (!success) {
358            __builtin_trap();
359        }
360        // The char-sized overloads of operator<< here print
361        // the character value, not the numeric value, so cast up.
362        member_value << static_cast<int>(value);
363        break;
364    }
365    case types::PrimitiveSubtype::kInt16: {
366        int16_t value;
367        bool success = library->ParseIntegerConstant(constant, &value);
368        if (!success) {
369            __builtin_trap();
370        }
371        member_value << value;
372        break;
373    }
374    case types::PrimitiveSubtype::kInt32: {
375        int32_t value;
376        bool success = library->ParseIntegerConstant(constant, &value);
377        if (!success) {
378            __builtin_trap();
379        }
380        member_value << value;
381        break;
382    }
383    case types::PrimitiveSubtype::kInt64: {
384        int64_t value;
385        bool success = library->ParseIntegerConstant(constant, &value);
386        if (!success) {
387            __builtin_trap();
388        }
389        member_value << value;
390        break;
391    }
392    case types::PrimitiveSubtype::kUint8: {
393        uint8_t value;
394        bool success = library->ParseIntegerConstant(constant, &value);
395        if (!success) {
396            __builtin_trap();
397        }
398        // The char-sized overloads of operator<< here print
399        // the character value, not the numeric value, so cast up.
400        member_value << static_cast<unsigned int>(value);
401        break;
402    }
403    case types::PrimitiveSubtype::kUint16: {
404        uint16_t value;
405        bool success = library->ParseIntegerConstant(constant, &value);
406        if (!success) {
407            __builtin_trap();
408        }
409        member_value << value;
410        break;
411    }
412    case types::PrimitiveSubtype::kUint32: {
413        uint32_t value;
414        bool success = library->ParseIntegerConstant(constant, &value);
415        if (!success) {
416            __builtin_trap();
417        }
418        member_value << value;
419        break;
420    }
421    case types::PrimitiveSubtype::kUint64: {
422        uint64_t value;
423        bool success = library->ParseIntegerConstant(constant, &value);
424        if (!success) {
425            __builtin_trap();
426        }
427        member_value << value;
428        break;
429    }
430    case types::PrimitiveSubtype::kBool:
431    case types::PrimitiveSubtype::kFloat32:
432    case types::PrimitiveSubtype::kFloat64:
433        assert(false && "bad primitive type for an enum");
434        break;
435    }
436
437    *out_value = member_value.str();
438}
439
440std::vector<uint32_t> ArrayCounts(const flat::Library* library, const flat::Type* type) {
441    std::vector<uint32_t> array_counts;
442    for (;;) {
443        switch (type->kind) {
444        default: { return array_counts; }
445        case flat::Type::Kind::kArray: {
446            auto array_type = static_cast<const flat::ArrayType*>(type);
447            uint32_t element_count = array_type->element_count.Value();
448            array_counts.push_back(element_count);
449            type = array_type->element_type.get();
450            continue;
451        }
452        }
453    }
454}
455
456flat::Decl::Kind GetDeclKind(const flat::Library* library, const flat::Type* type) {
457    if (type->kind != flat::Type::Kind::kIdentifier)
458        return flat::Decl::Kind::kConst;
459    auto identifier_type = static_cast<const flat::IdentifierType*>(type);
460    auto named_decl = library->LookupDeclByName(identifier_type->name);
461    assert(named_decl && "library must contain declaration");
462    return named_decl->kind;
463}
464
465template <typename T>
466CGenerator::Member CreateMember(const flat::Library* library, const T& decl) {
467    std::string name = NameIdentifier(decl.name);
468    const flat::Type* type = decl.type.get();
469    auto decl_kind = GetDeclKind(library, type);
470    auto type_name = NameFlatCType(type, decl_kind);
471    std::vector<uint32_t> array_counts = ArrayCounts(library, type);
472    std::string element_type_name;
473    if (type->kind == flat::Type::Kind::kVector) {
474        auto vector_type = static_cast<const flat::VectorType*>(type);
475        const flat::Type* element_type = vector_type->element_type.get();
476        element_type_name = NameFlatCType(element_type, GetDeclKind(library, element_type));
477    }
478    types::Nullability nullability = types::Nullability::kNonnullable;
479    if (type->kind == flat::Type::Kind::kIdentifier) {
480        auto identifier_type = static_cast<const flat::IdentifierType*>(type);
481        nullability = identifier_type->nullability;
482    }
483    return CGenerator::Member{
484        type->kind,
485        decl_kind,
486        std::move(type_name),
487        std::move(name),
488        std::move(element_type_name),
489        std::move(array_counts),
490        nullability,
491    };
492}
493
494std::vector<CGenerator::Member>
495GenerateMembers(const flat::Library* library,
496                const std::vector<flat::Union::Member>& union_members) {
497    std::vector<CGenerator::Member> members;
498    members.reserve(union_members.size());
499    for (const auto& union_member : union_members) {
500        members.push_back(CreateMember(library, union_member));
501    }
502    return members;
503}
504
505void GetMethodParameters(const flat::Library* library,
506                         const CGenerator::NamedMethod& method_info,
507                         std::vector<CGenerator::Member>* request,
508                         std::vector<CGenerator::Member>* response) {
509    if (request) {
510        request->reserve(method_info.request->parameters.size());
511        for (const auto& parameter : method_info.request->parameters) {
512            request->push_back(CreateMember(library, parameter));
513        }
514    }
515
516    if (response && method_info.response) {
517        response->reserve(method_info.request->parameters.size());
518        for (const auto& parameter : method_info.response->parameters) {
519            response->push_back(CreateMember(library, parameter));
520        }
521    }
522}
523
524} // namespace
525
526void CGenerator::GeneratePrologues() {
527    EmitFileComment(&file_);
528    EmitHeaderGuard(&file_);
529    EmitBlank(&file_);
530    EmitIncludeHeader(&file_, "<stdalign.h>");
531    EmitIncludeHeader(&file_, "<stdbool.h>");
532    EmitIncludeHeader(&file_, "<stdint.h>");
533    EmitIncludeHeader(&file_, "<zircon/fidl.h>");
534    EmitIncludeHeader(&file_, "<zircon/syscalls/object.h>");
535    EmitIncludeHeader(&file_, "<zircon/types.h>");
536    // Dependencies are in pointer order... change to a deterministic
537    // ordering prior to output.
538    std::set<std::string> add_includes;
539    for (const auto& dep_library : library_->dependencies()) {
540        if (dep_library == library_)
541            continue;
542        if (dep_library->HasAttribute("Internal"))
543            continue;
544        add_includes.insert(NameLibraryCHeader(dep_library->name()));
545    }
546    for (const auto& include : add_includes) {
547        EmitIncludeHeader(&file_, "<" + include + ">");
548    }
549    EmitBlank(&file_);
550    EmitBeginExternC(&file_);
551    EmitBlank(&file_);
552}
553
554void CGenerator::GenerateEpilogues() {
555    EmitEndExternC(&file_);
556}
557
558void CGenerator::GenerateIntegerDefine(StringView name, types::PrimitiveSubtype subtype,
559                                       StringView value) {
560    std::string literal_macro = NamePrimitiveIntegerCConstantMacro(subtype);
561    file_ << "#define " << name << " " << literal_macro << "(" << value << ")\n";
562}
563
564void CGenerator::GeneratePrimitiveDefine(StringView name, types::PrimitiveSubtype subtype,
565                                         StringView value) {
566    switch (subtype) {
567    case types::PrimitiveSubtype::kInt8:
568    case types::PrimitiveSubtype::kInt16:
569    case types::PrimitiveSubtype::kInt32:
570    case types::PrimitiveSubtype::kInt64:
571    case types::PrimitiveSubtype::kUint8:
572    case types::PrimitiveSubtype::kUint16:
573    case types::PrimitiveSubtype::kUint32:
574    case types::PrimitiveSubtype::kUint64: {
575        std::string literal_macro = NamePrimitiveIntegerCConstantMacro(subtype);
576        file_ << "#define " << name << " " << literal_macro << "(" << value << ")\n";
577        break;
578    }
579    case types::PrimitiveSubtype::kBool:
580    case types::PrimitiveSubtype::kFloat32:
581    case types::PrimitiveSubtype::kFloat64: {
582        file_ << "#define " << name << " "
583              << "(" << value << ")\n";
584        break;
585    }
586    default:
587        abort();
588    }
589}
590
591void CGenerator::GenerateStringDefine(StringView name, StringView value) {
592    file_ << "#define " << name << " " << value << "\n";
593}
594
595void CGenerator::GenerateIntegerTypedef(types::PrimitiveSubtype subtype, StringView name) {
596    std::string underlying_type = NamePrimitiveCType(subtype);
597    file_ << "typedef " << underlying_type << " " << name << ";\n";
598}
599
600void CGenerator::GenerateStructTypedef(StringView name) {
601    file_ << "typedef struct " << name << " " << name << ";\n";
602}
603
604void CGenerator::GenerateStructDeclaration(StringView name, const std::vector<Member>& members) {
605    file_ << "struct " << name << " {\n";
606    file_ << kIndent << "FIDL_ALIGNDECL\n";
607    for (const auto& member : members) {
608        file_ << kIndent;
609        EmitMemberDecl(&file_, member);
610        file_ << ";\n";
611    }
612    file_ << "};\n";
613}
614
615void CGenerator::GenerateTaggedUnionDeclaration(StringView name,
616                                                const std::vector<Member>& members) {
617    file_ << "struct " << name << " {\n";
618    file_ << kIndent << "FIDL_ALIGNDECL\n";
619    file_ << kIndent << "fidl_union_tag_t tag;\n";
620    file_ << kIndent << "union {\n";
621    for (const auto& member : members) {
622        file_ << kIndent << kIndent;
623        EmitMemberDecl(&file_, member);
624        file_ << ";\n";
625    }
626    file_ << kIndent << "};\n";
627    file_ << "};\n";
628}
629
630// TODO(TO-702) These should maybe check for global name
631// collisions? Otherwise, is there some other way they should fail?
632std::map<const flat::Decl*, CGenerator::NamedConst>
633CGenerator::NameConsts(const std::vector<std::unique_ptr<flat::Const>>& const_infos) {
634    std::map<const flat::Decl*, NamedConst> named_consts;
635    for (const auto& const_info : const_infos) {
636        named_consts.emplace(const_info.get(), NamedConst{NameName(const_info->name, "_", "_"), *const_info});
637    }
638    return named_consts;
639}
640
641std::map<const flat::Decl*, CGenerator::NamedEnum>
642CGenerator::NameEnums(const std::vector<std::unique_ptr<flat::Enum>>& enum_infos) {
643    std::map<const flat::Decl*, NamedEnum> named_enums;
644    for (const auto& enum_info : enum_infos) {
645        std::string enum_name = NameName(enum_info->name, "_", "_");
646        named_enums.emplace(enum_info.get(), NamedEnum{std::move(enum_name), *enum_info});
647    }
648    return named_enums;
649}
650
651std::map<const flat::Decl*, CGenerator::NamedInterface>
652CGenerator::NameInterfaces(const std::vector<std::unique_ptr<flat::Interface>>& interface_infos) {
653    std::map<const flat::Decl*, NamedInterface> named_interfaces;
654    for (const auto& interface_info : interface_infos) {
655        NamedInterface named_interface;
656        named_interface.c_name = NameInterface(*interface_info);
657        if (interface_info->HasAttribute("Discoverable")) {
658            named_interface.discoverable_name = NameDiscoverable(*interface_info);
659        }
660        for (const auto& method_pointer : interface_info->all_methods) {
661            assert(method_pointer != nullptr);
662            const auto& method = *method_pointer;
663            NamedMethod named_method;
664            std::string method_name = NameMethod(named_interface.c_name, method);
665            named_method.ordinal = method.ordinal.Value();
666            named_method.ordinal_name = NameOrdinal(method_name);
667            named_method.identifier = NameIdentifier(method.name);
668            named_method.c_name = method_name;
669            if (method.maybe_request != nullptr) {
670                std::string c_name = NameMessage(method_name, types::MessageKind::kRequest);
671                std::string coded_name = NameTable(c_name);
672                named_method.request = std::make_unique<NamedMessage>(NamedMessage{
673                    std::move(c_name), std::move(coded_name),
674                    method.maybe_request->parameters, method.maybe_request->typeshape});
675            }
676            if (method.maybe_response != nullptr) {
677                if (method.maybe_request == nullptr) {
678                    std::string c_name =
679                        NameMessage(method_name, types::MessageKind::kEvent);
680                    std::string coded_name = NameTable(c_name);
681                    named_method.response = std::make_unique<NamedMessage>(
682                        NamedMessage{std::move(c_name), std::move(coded_name),
683                                     method.maybe_response->parameters,
684                                     method.maybe_response->typeshape});
685                } else {
686                    std::string c_name = NameMessage(method_name, types::MessageKind::kResponse);
687                    std::string coded_name = NameTable(c_name);
688                    named_method.response = std::make_unique<NamedMessage>(
689                        NamedMessage{std::move(c_name), std::move(coded_name),
690                                     method.maybe_response->parameters,
691                                     method.maybe_response->typeshape});
692                }
693            }
694            named_interface.methods.push_back(std::move(named_method));
695        }
696        named_interfaces.emplace(interface_info.get(), std::move(named_interface));
697    }
698    return named_interfaces;
699}
700
701std::map<const flat::Decl*, CGenerator::NamedStruct>
702CGenerator::NameStructs(const std::vector<std::unique_ptr<flat::Struct>>& struct_infos) {
703    std::map<const flat::Decl*, NamedStruct> named_structs;
704    for (const auto& struct_info : struct_infos) {
705        std::string c_name = NameName(struct_info->name, "_", "_");
706        std::string coded_name = c_name + "Coded";
707        named_structs.emplace(struct_info.get(),
708                              NamedStruct{std::move(c_name), std::move(coded_name), *struct_info});
709    }
710    return named_structs;
711}
712
713std::map<const flat::Decl*, CGenerator::NamedTable>
714CGenerator::NameTables(const std::vector<std::unique_ptr<flat::Table>>& table_infos) {
715    std::map<const flat::Decl*, NamedTable> named_tables;
716    for (const auto& table_info : table_infos) {
717        std::string c_name = NameName(table_info->name, "_", "_");
718        std::string coded_name = c_name + "Coded";
719        named_tables.emplace(table_info.get(),
720                             NamedTable{std::move(c_name), std::move(coded_name), *table_info});
721    }
722    return named_tables;
723}
724
725std::map<const flat::Decl*, CGenerator::NamedUnion>
726CGenerator::NameUnions(const std::vector<std::unique_ptr<flat::Union>>& union_infos) {
727    std::map<const flat::Decl*, NamedUnion> named_unions;
728    for (const auto& union_info : union_infos) {
729        std::string union_name = NameName(union_info->name, "_", "_");
730        named_unions.emplace(union_info.get(), NamedUnion{std::move(union_name), *union_info});
731    }
732    return named_unions;
733}
734
735void CGenerator::ProduceConstForwardDeclaration(const NamedConst& named_const) {
736    // TODO(TO-702)
737}
738
739void CGenerator::ProduceEnumForwardDeclaration(const NamedEnum& named_enum) {
740    types::PrimitiveSubtype subtype = named_enum.enum_info.type;
741    GenerateIntegerTypedef(subtype, named_enum.name);
742    for (const auto& member : named_enum.enum_info.members) {
743        std::string member_name = named_enum.name + "_" + NameIdentifier(member.name);
744        std::string member_value;
745        EnumValue(named_enum.enum_info.type, member.value.get(), library_, &member_value);
746        GenerateIntegerDefine(member_name, subtype, std::move(member_value));
747    }
748
749    EmitBlank(&file_);
750}
751
752void CGenerator::ProduceInterfaceForwardDeclaration(const NamedInterface& named_interface) {
753    if (!named_interface.discoverable_name.empty()) {
754        file_ << "#define " << named_interface.c_name << "_Name \"" << named_interface.discoverable_name << "\"\n";
755    }
756    for (const auto& method_info : named_interface.methods) {
757        {
758            IOFlagsGuard reset_flags(&file_);
759            file_ << "#define " << method_info.ordinal_name << " ((uint32_t)0x"
760                  << std::uppercase << std::hex << method_info.ordinal << std::dec << ")\n";
761        }
762        if (method_info.request)
763            GenerateStructTypedef(method_info.request->c_name);
764        if (method_info.response)
765            GenerateStructTypedef(method_info.response->c_name);
766    }
767}
768
769void CGenerator::ProduceStructForwardDeclaration(const NamedStruct& named_struct) {
770    GenerateStructTypedef(named_struct.c_name);
771}
772
773void CGenerator::ProduceTableForwardDeclaration(const NamedTable& named_struct) {
774    GenerateStructTypedef(named_struct.c_name);
775}
776
777void CGenerator::ProduceUnionForwardDeclaration(const NamedUnion& named_union) {
778    GenerateStructTypedef(named_union.name);
779}
780
781void CGenerator::ProduceInterfaceExternDeclaration(const NamedInterface& named_interface) {
782    for (const auto& method_info : named_interface.methods) {
783        if (method_info.request)
784            file_ << "extern const fidl_type_t " << method_info.request->coded_name << ";\n";
785        if (method_info.response)
786            file_ << "extern const fidl_type_t " << method_info.response->coded_name
787                  << ";\n";
788    }
789}
790
791void CGenerator::ProduceConstDeclaration(const NamedConst& named_const) {
792    const flat::Const& ci = named_const.const_info;
793
794    // Some constants are not literals.  Odd.
795    if (ci.value->kind != flat::Constant::Kind::kLiteral) {
796        return;
797    }
798
799    switch (ci.type->kind) {
800    case flat::Type::Kind::kPrimitive:
801        GeneratePrimitiveDefine(named_const.name,
802                                static_cast<flat::PrimitiveType*>(ci.type.get())->subtype,
803                                static_cast<flat::LiteralConstant*>(ci.value.get())->literal->location().data());
804        break;
805    case flat::Type::Kind::kString:
806        GenerateStringDefine(named_const.name,
807                             static_cast<flat::LiteralConstant*>(ci.value.get())->literal->location().data());
808        break;
809    default:
810        abort();
811    }
812
813    EmitBlank(&file_);
814}
815
816void CGenerator::ProduceMessageDeclaration(const NamedMessage& named_message) {
817    std::vector<CGenerator::Member> members;
818    members.reserve(1 + named_message.parameters.size());
819    members.push_back(MessageHeader());
820    for (const auto& parameter : named_message.parameters) {
821        members.push_back(CreateMember(library_, parameter));
822    }
823
824    GenerateStructDeclaration(named_message.c_name, members);
825
826    EmitBlank(&file_);
827}
828
829void CGenerator::ProduceInterfaceDeclaration(const NamedInterface& named_interface) {
830    for (const auto& method_info : named_interface.methods) {
831        if (method_info.request)
832            ProduceMessageDeclaration(*method_info.request);
833        if (method_info.response)
834            ProduceMessageDeclaration(*method_info.response);
835    }
836}
837
838void CGenerator::ProduceStructDeclaration(const NamedStruct& named_struct) {
839    std::vector<CGenerator::Member> members;
840    members.reserve(named_struct.struct_info.members.size());
841    for (const auto& struct_member : named_struct.struct_info.members) {
842        members.push_back(CreateMember(library_, struct_member));
843    }
844
845    GenerateStructDeclaration(named_struct.c_name, members);
846
847    EmitBlank(&file_);
848}
849
850void CGenerator::ProduceUnionDeclaration(const NamedUnion& named_union) {
851    std::vector<CGenerator::Member> members =
852        GenerateMembers(library_, named_union.union_info.members);
853    GenerateTaggedUnionDeclaration(named_union.name, members);
854
855    uint32_t tag = 0u;
856    for (const auto& member : named_union.union_info.members) {
857        std::string tag_name = NameUnionTag(named_union.name, member);
858        auto union_tag_type = types::PrimitiveSubtype::kUint32;
859        std::ostringstream value;
860        value << tag;
861        GenerateIntegerDefine(std::move(tag_name), union_tag_type, value.str());
862        ++tag;
863    }
864
865    EmitBlank(&file_);
866}
867
868void CGenerator::ProduceInterfaceClientDeclaration(const NamedInterface& named_interface) {
869    for (const auto& method_info : named_interface.methods) {
870        if (!method_info.request)
871            continue;
872        std::vector<Member> request;
873        std::vector<Member> response;
874        GetMethodParameters(library_, method_info, &request, &response);
875        EmitClientMethodDecl(&file_, method_info.c_name, request, response);
876        file_ << ";\n";
877    }
878
879    EmitBlank(&file_);
880}
881
882void CGenerator::ProduceInterfaceClientImplementation(const NamedInterface& named_interface) {
883    for (const auto& method_info : named_interface.methods) {
884        if (!method_info.request)
885            continue;
886        std::vector<Member> request;
887        std::vector<Member> response;
888        GetMethodParameters(library_, method_info, &request, &response);
889
890        size_t count = CountSecondaryObjects(request);
891        size_t hcount = method_info.request->typeshape.MaxHandles();
892        bool encode = ((count > 0) || (hcount > 0));
893
894        EmitClientMethodDecl(&file_, method_info.c_name, request, response);
895        file_ << " {\n";
896        file_ << kIndent << "uint32_t _wr_num_bytes = sizeof(" << method_info.request->c_name << ")";
897        EmitMeasureInParams(&file_, request);
898        file_ << ";\n";
899        file_ << kIndent << "FIDL_ALIGNDECL char _wr_bytes[_wr_num_bytes];\n";
900        file_ << kIndent << method_info.request->c_name << "* _request = (" << method_info.request->c_name << "*)_wr_bytes;\n";
901        file_ << kIndent << "memset(_wr_bytes, 0, sizeof(_wr_bytes));\n";
902        file_ << kIndent << "_request->hdr.ordinal = " << method_info.ordinal << ";\n";
903        EmitLinearizeMessage(&file_, "_request", "_wr_bytes", request);
904        if (encode) {
905            file_ << kIndent << "zx_handle_t _handles[ZX_CHANNEL_MAX_MSG_HANDLES];\n";
906            file_ << kIndent << "uint32_t _wr_num_handles = 0u;\n";
907            file_ << kIndent << "zx_status_t _status = fidl_encode(&" << method_info.request->coded_name
908                  << ", _wr_bytes, _wr_num_bytes, _handles, ZX_CHANNEL_MAX_MSG_HANDLES"
909                  << ", &_wr_num_handles, NULL);\n";
910            file_ << kIndent << "if (_status != ZX_OK)\n";
911            file_ << kIndent << kIndent << "return _status;\n";
912        } else {
913            file_ << kIndent << "// OPTIMIZED AWAY fidl_encode() of POD-only request\n";
914        }
915        if (!method_info.response) {
916            if (encode) {
917                file_ << kIndent << "return zx_channel_write(_channel, 0u, _wr_bytes, _wr_num_bytes, _handles, _wr_num_handles);\n";
918            } else {
919                file_ << kIndent << "return zx_channel_write(_channel, 0u, _wr_bytes, _wr_num_bytes, NULL, 0);\n";
920            }
921        } else {
922            file_ << kIndent << "uint32_t _rd_num_bytes = sizeof(" << method_info.response->c_name << ")";
923            EmitMeasureOutParams(&file_, response);
924            file_ << ";\n";
925            file_ << kIndent << "FIDL_ALIGNDECL char _rd_bytes[_rd_num_bytes];\n";
926            if (!encode) {
927                file_ << kIndent << "zx_handle_t _handles[ZX_CHANNEL_MAX_MSG_HANDLES];\n";
928            }
929            if (!response.empty())
930                file_ << kIndent << method_info.response->c_name << "* _response = (" << method_info.response->c_name << "*)_rd_bytes;\n";
931            file_ << kIndent << "zx_channel_call_args_t _args = {\n";
932            file_ << kIndent << kIndent << ".wr_bytes = _wr_bytes,\n";
933            if (encode) {
934                file_ << kIndent << kIndent << ".wr_handles = _handles,\n";
935            } else {
936                file_ << kIndent << kIndent << ".wr_handles = NULL,\n";
937            }
938            file_ << kIndent << kIndent << ".rd_bytes = _rd_bytes,\n";
939            file_ << kIndent << kIndent << ".rd_handles = _handles,\n";
940            file_ << kIndent << kIndent << ".wr_num_bytes = _wr_num_bytes,\n";
941            if (encode) {
942                file_ << kIndent << kIndent << ".wr_num_handles = _wr_num_handles,\n";
943            } else {
944                file_ << kIndent << kIndent << ".wr_num_handles = 0,\n";
945            }
946            file_ << kIndent << kIndent << ".rd_num_bytes = _rd_num_bytes,\n";
947            file_ << kIndent << kIndent << ".rd_num_handles = ZX_CHANNEL_MAX_MSG_HANDLES,\n";
948            file_ << kIndent << "};\n";
949
950            file_ << kIndent << "uint32_t _actual_num_bytes = 0u;\n";
951            file_ << kIndent << "uint32_t _actual_num_handles = 0u;\n";
952            if (encode) {
953                file_ << kIndent;
954            } else {
955                file_ << kIndent << "zx_status_t ";
956            }
957            file_ << "_status = zx_channel_call(_channel, 0u, ZX_TIME_INFINITE, &_args, &_actual_num_bytes, &_actual_num_handles);\n";
958            file_ << kIndent << "if (_status != ZX_OK)\n";
959            file_ << kIndent << kIndent << "return _status;\n";
960
961            // We check that we have enough capacity to copy out the parameters
962            // before decoding the message so that we can close the handles
963            // using |_handles| rather than trying to find them in the decoded
964            // message.
965            count = CountSecondaryObjects(response);
966            if (count > 0u) {
967                file_ << kIndent << "if ";
968                if (count > 1u)
969                    file_ << "(";
970                size_t i = 0;
971                for (const auto& member : response) {
972                    if (member.kind == flat::Type::Kind::kVector) {
973                        if (i++ > 0u)
974                            file_ << " || ";
975                        file_ << "(_response->" << member.name << ".count > " << member.name << "_capacity)";
976                    } else if (member.kind == flat::Type::Kind::kString) {
977                        if (i++ > 0u)
978                            file_ << " || ";
979                        file_ << "(_response->" << member.name << ".size > " << member.name << "_capacity)";
980                    } else if (IsStoredOutOfLine(member)) {
981                        if (i++ > 0u)
982                            file_ << " || ";
983                        file_ << "((uintptr_t)_response->" << member.name << " == FIDL_ALLOC_PRESENT && out_" << member.name << " == NULL)";
984                    }
985                }
986                if (count > 1u)
987                    file_ << ")";
988                file_ << " {\n";
989                file_ << kIndent << kIndent << "zx_handle_close_many(_handles, _actual_num_handles);\n";
990                file_ << kIndent << kIndent << "return ZX_ERR_BUFFER_TOO_SMALL;\n";
991                file_ << kIndent << "}\n";
992            }
993
994            hcount = method_info.response->typeshape.MaxHandles();
995            if ((count == 0) && (hcount == 0)) {
996                file_ << kIndent << "// OPTIMIZED AWAY fidl_decode() of POD-only response\n";
997                file_ << kIndent << "if (_actual_num_handles > 0) {\n";
998                file_ << kIndent << kIndent << "zx_handle_close_many(_handles, _actual_num_handles);\n";
999                file_ << kIndent << kIndent << "return ZX_ERR_INTERNAL;\n"; // WHAT ERROR?
1000                file_ << kIndent << "}\n";
1001            } else {
1002                // TODO(FIDL-162): Validate the response ordinal. C++ bindings also need to do that.
1003                file_ << kIndent << "_status = fidl_decode(&" << method_info.response->coded_name
1004                      << ", _rd_bytes, _actual_num_bytes, _handles, _actual_num_handles, NULL);\n";
1005                file_ << kIndent << "if (_status != ZX_OK)\n";
1006                file_ << kIndent << kIndent << "return _status;\n";
1007            }
1008
1009            for (const auto& member : response) {
1010                const auto& name = member.name;
1011                switch (member.kind) {
1012                case flat::Type::Kind::kArray:
1013                    file_ << kIndent << "memcpy(out_" << name << ", _response->" << name << ", sizeof(out_" << name << "));\n";
1014                    break;
1015                case flat::Type::Kind::kVector:
1016                    file_ << kIndent << "memcpy(" << name << "_buffer, _response->" << name << ".data, sizeof(*" << name << "_buffer) * _response->" << name << ".count);\n";
1017                    file_ << kIndent << "*out_" << name << "_count = _response->" << name << ".count;\n";
1018                    break;
1019                case flat::Type::Kind::kString:
1020                    file_ << kIndent << "memcpy(" << name << "_buffer, _response->" << name << ".data, _response->" << name << ".size);\n";
1021                    file_ << kIndent << "*out_" << name << "_size = _response->" << name << ".size;\n";
1022                    break;
1023                case flat::Type::Kind::kHandle:
1024                case flat::Type::Kind::kRequestHandle:
1025                case flat::Type::Kind::kPrimitive:
1026                    file_ << kIndent << "*out_" << name << " = _response->" << name << ";\n";
1027                    break;
1028                case flat::Type::Kind::kIdentifier:
1029                    switch (member.decl_kind) {
1030                    case flat::Decl::Kind::kConst:
1031                        assert(false && "bad decl kind for member");
1032                        break;
1033                    case flat::Decl::Kind::kEnum:
1034                    case flat::Decl::Kind::kInterface:
1035                        file_ << kIndent << "*out_" << name << " = _response->" << name << ";\n";
1036                        break;
1037                    case flat::Decl::Kind::kTable:
1038                        assert(false && "c-codegen for tables not yet implemented");
1039                        break;
1040                    case flat::Decl::Kind::kStruct:
1041                    case flat::Decl::Kind::kUnion:
1042                        switch (member.nullability) {
1043                        case types::Nullability::kNullable:
1044                            file_ << kIndent << "if (_response->" << name << ") {\n";
1045                            file_ << kIndent << kIndent << "*out_" << name << " = *(_response->" << name << ");\n";
1046                            file_ << kIndent << "} else {\n";
1047                            // We don't have a great way of signaling that the optional response member
1048                            // was not in the message. That means these bindings aren't particularly
1049                            // useful when the client needs to extract that bit. The best we can do is
1050                            // zero out the value to make sure the client has defined behavior.
1051                            //
1052                            // In many cases, the response contains other information (e.g., a status code)
1053                            // that lets the client do something reasonable.
1054                            file_ << kIndent << kIndent << "memset(out_" << name << ", 0, sizeof(*out_" << name << "));\n";
1055                            file_ << kIndent << "}\n";
1056                            break;
1057                        case types::Nullability::kNonnullable:
1058                            file_ << kIndent << "*out_" << name << " = _response->" << name << ";\n";
1059                            break;
1060                        }
1061                        break;
1062                    }
1063                    break;
1064                }
1065            }
1066
1067            file_ << kIndent << "return ZX_OK;\n";
1068        }
1069        file_ << "}\n\n";
1070    }
1071} // namespace fidl
1072
1073void CGenerator::ProduceInterfaceServerDeclaration(const NamedInterface& named_interface) {
1074    file_ << "typedef struct " << named_interface.c_name << "_ops {\n";
1075    for (const auto& method_info : named_interface.methods) {
1076        if (!method_info.request)
1077            continue;
1078        std::vector<Member> request;
1079        GetMethodParameters(library_, method_info, &request, nullptr);
1080        bool has_response = method_info.response != nullptr;
1081        file_ << kIndent;
1082        EmitServerMethodDecl(&file_, method_info.identifier, request, has_response);
1083        file_ << ";\n";
1084    }
1085    file_ << "} " << named_interface.c_name << "_ops_t;\n\n";
1086
1087    EmitServerDispatchDecl(&file_, named_interface.c_name);
1088    file_ << ";\n";
1089    EmitServerTryDispatchDecl(&file_, named_interface.c_name);
1090    file_ << ";\n\n";
1091
1092    for (const auto& method_info : named_interface.methods) {
1093        if (!method_info.request || !method_info.response)
1094            continue;
1095        std::vector<Member> response;
1096        GetMethodParameters(library_, method_info, nullptr, &response);
1097        EmitServerReplyDecl(&file_, method_info.c_name, response);
1098        file_ << ";\n";
1099    }
1100
1101    EmitBlank(&file_);
1102}
1103
1104void CGenerator::ProduceInterfaceServerImplementation(const NamedInterface& named_interface) {
1105    EmitServerTryDispatchDecl(&file_, named_interface.c_name);
1106    file_ << " {\n";
1107    file_ << kIndent << "if (msg->num_bytes < sizeof(fidl_message_header_t)) {\n";
1108    file_ << kIndent << kIndent << "zx_handle_close_many(msg->handles, msg->num_handles);\n";
1109    file_ << kIndent << kIndent << "return ZX_ERR_INVALID_ARGS;\n";
1110    file_ << kIndent << "}\n";
1111    file_ << kIndent << "fidl_message_header_t* hdr = (fidl_message_header_t*)msg->bytes;\n";
1112    file_ << kIndent << "zx_status_t status = ZX_OK;\n";
1113    file_ << kIndent << "switch (hdr->ordinal) {\n";
1114
1115    for (const auto& method_info : named_interface.methods) {
1116        if (!method_info.request)
1117            continue;
1118        file_ << kIndent << "case " << method_info.ordinal_name << ": {\n";
1119        file_ << kIndent << kIndent << "status = fidl_decode_msg(&" << method_info.request->coded_name << ", msg, NULL);\n";
1120        file_ << kIndent << kIndent << "if (status != ZX_OK)\n";
1121        file_ << kIndent << kIndent << kIndent << "break;\n";
1122        std::vector<Member> request;
1123        GetMethodParameters(library_, method_info, &request, nullptr);
1124        if (!request.empty())
1125            file_ << kIndent << kIndent << method_info.request->c_name << "* request = (" << method_info.request->c_name << "*)msg->bytes;\n";
1126        file_ << kIndent << kIndent << "status = (*ops->" << method_info.identifier << ")(ctx";
1127        for (const auto& member : request) {
1128            switch (member.kind) {
1129            case flat::Type::Kind::kArray:
1130            case flat::Type::Kind::kHandle:
1131            case flat::Type::Kind::kRequestHandle:
1132            case flat::Type::Kind::kPrimitive:
1133                file_ << ", request->" << member.name;
1134                break;
1135            case flat::Type::Kind::kVector:
1136                file_ << ", (" << member.element_type << "*)request->" << member.name << ".data"
1137                      << ", request->" << member.name << ".count";
1138                break;
1139            case flat::Type::Kind::kString:
1140                file_ << ", request->" << member.name << ".data"
1141                      << ", request->" << member.name << ".size";
1142                break;
1143            case flat::Type::Kind::kIdentifier:
1144                switch (member.decl_kind) {
1145                case flat::Decl::Kind::kConst:
1146                    assert(false && "bad decl kind for member");
1147                    break;
1148                case flat::Decl::Kind::kEnum:
1149                case flat::Decl::Kind::kInterface:
1150                    file_ << ", request->" << member.name;
1151                    break;
1152                case flat::Decl::Kind::kTable:
1153                    assert(false && "c-codegen for tables not yet implemented");
1154                    break;
1155                case flat::Decl::Kind::kStruct:
1156                case flat::Decl::Kind::kUnion:
1157                    switch (member.nullability) {
1158                    case types::Nullability::kNullable:
1159                        file_ << ", request->" << member.name;
1160                        break;
1161                    case types::Nullability::kNonnullable:
1162                        file_ << ", &(request->" << member.name << ")";
1163                        break;
1164                    }
1165                    break;
1166                }
1167            }
1168        }
1169        if (method_info.response != nullptr)
1170            file_ << ", txn";
1171        file_ << ");\n";
1172        file_ << kIndent << kIndent << "break;\n";
1173        file_ << kIndent << "}\n";
1174    }
1175    file_ << kIndent << "default: {\n";
1176    file_ << kIndent << kIndent << "return ZX_ERR_NOT_SUPPORTED;\n";
1177    file_ << kIndent << "}\n";
1178    file_ << kIndent << "}\n";
1179    file_ << kIndent << "if ("
1180          << "status != ZX_OK && "
1181          << "status != ZX_ERR_STOP && "
1182          << "status != ZX_ERR_NEXT && "
1183          << "status != ZX_ERR_ASYNC) {\n";
1184    file_ << kIndent << kIndent << "return ZX_ERR_INTERNAL;\n";
1185    file_ << kIndent << "} else {\n";
1186    file_ << kIndent << kIndent << "return status;\n";
1187    file_ << kIndent << "}\n";
1188    file_ << "}\n\n";
1189
1190    EmitServerDispatchDecl(&file_, named_interface.c_name);
1191    file_ << " {\n";
1192    file_ << kIndent << "zx_status_t status = "
1193          << named_interface.c_name << "_try_dispatch(ctx, txn, msg, ops);\n";
1194    file_ << kIndent << "if (status == ZX_ERR_NOT_SUPPORTED)\n";
1195    file_ << kIndent << kIndent << "zx_handle_close_many(msg->handles, msg->num_handles);\n";
1196    file_ << kIndent << "return status;\n";
1197    file_ << "}\n\n";
1198
1199    for (const auto& method_info : named_interface.methods) {
1200        if (!method_info.request || !method_info.response)
1201            continue;
1202        std::vector<Member> response;
1203        GetMethodParameters(library_, method_info, nullptr, &response);
1204
1205        size_t hcount = method_info.response->typeshape.MaxHandles();
1206        bool encode = ((CountSecondaryObjects(response) > 0) || (hcount > 0));
1207
1208        EmitServerReplyDecl(&file_, method_info.c_name, response);
1209        file_ << " {\n";
1210        file_ << kIndent << "uint32_t _wr_num_bytes = sizeof(" << method_info.response->c_name << ")";
1211        EmitMeasureInParams(&file_, response);
1212        file_ << ";\n";
1213        file_ << kIndent << "char _wr_bytes[_wr_num_bytes];\n";
1214        file_ << kIndent << method_info.response->c_name << "* _response = (" << method_info.response->c_name << "*)_wr_bytes;\n";
1215        file_ << kIndent << "memset(_wr_bytes, 0, sizeof(_wr_bytes));\n";
1216        file_ << kIndent << "_response->hdr.ordinal = " << method_info.ordinal << ";\n";
1217        EmitLinearizeMessage(&file_, "_response", "_wr_bytes", response);
1218        if (encode) {
1219            file_ << kIndent << "zx_handle_t _handles[ZX_CHANNEL_MAX_MSG_HANDLES];\n";
1220        }
1221        file_ << kIndent << "fidl_msg_t _msg = {\n";
1222        file_ << kIndent << kIndent << ".bytes = _wr_bytes,\n";
1223        if (encode) {
1224            file_ << kIndent << kIndent << ".handles = _handles,\n";
1225        } else {
1226            file_ << kIndent << kIndent << ".handles = NULL,\n";
1227        }
1228        file_ << kIndent << kIndent << ".num_bytes = _wr_num_bytes,\n";
1229        if (encode) {
1230            file_ << kIndent << kIndent << ".num_handles = ZX_CHANNEL_MAX_MSG_HANDLES,\n";
1231        } else {
1232            file_ << kIndent << kIndent << ".num_handles = 0,\n";
1233        }
1234        file_ << kIndent << "};\n";
1235        if (encode) {
1236            file_ << kIndent << "zx_status_t _status = fidl_encode_msg(&"
1237                  << method_info.response->coded_name << ", &_msg, &_msg.num_handles, NULL);\n";
1238            file_ << kIndent << "if (_status != ZX_OK)\n";
1239            file_ << kIndent << kIndent << "return _status;\n";
1240        } else {
1241            file_ << kIndent << "// OPTIMIZED AWAY fidl_encode() of POD-only reply\n";
1242        }
1243        file_ << kIndent << "return _txn->reply(_txn, &_msg);\n";
1244        file_ << "}\n\n";
1245    }
1246}
1247
1248std::ostringstream CGenerator::ProduceHeader() {
1249    GeneratePrologues();
1250
1251    std::map<const flat::Decl*, NamedConst> named_consts =
1252        NameConsts(library_->const_declarations_);
1253    std::map<const flat::Decl*, NamedEnum> named_enums = NameEnums(library_->enum_declarations_);
1254    std::map<const flat::Decl*, NamedInterface> named_interfaces =
1255        NameInterfaces(library_->interface_declarations_);
1256    std::map<const flat::Decl*, NamedStruct> named_structs =
1257        NameStructs(library_->struct_declarations_);
1258    std::map<const flat::Decl*, NamedTable> named_tables =
1259        NameTables(library_->table_declarations_);
1260    std::map<const flat::Decl*, NamedUnion> named_unions =
1261        NameUnions(library_->union_declarations_);
1262
1263    file_ << "\n// Forward declarations\n\n";
1264
1265    for (const auto* decl : library_->declaration_order_) {
1266        switch (decl->kind) {
1267        case flat::Decl::Kind::kConst: {
1268            auto iter = named_consts.find(decl);
1269            if (iter != named_consts.end()) {
1270                ProduceConstForwardDeclaration(iter->second);
1271            }
1272            break;
1273        }
1274        case flat::Decl::Kind::kEnum: {
1275            auto iter = named_enums.find(decl);
1276            if (iter != named_enums.end()) {
1277                ProduceEnumForwardDeclaration(iter->second);
1278            }
1279            break;
1280        }
1281        case flat::Decl::Kind::kInterface: {
1282            auto iter = named_interfaces.find(decl);
1283            if (iter != named_interfaces.end()) {
1284                ProduceInterfaceForwardDeclaration(iter->second);
1285            }
1286            break;
1287        }
1288        case flat::Decl::Kind::kStruct: {
1289            auto iter = named_structs.find(decl);
1290            if (iter != named_structs.end()) {
1291                ProduceStructForwardDeclaration(iter->second);
1292            }
1293            break;
1294        }
1295        case flat::Decl::Kind::kTable: {
1296            auto iter = named_tables.find(decl);
1297            if (iter != named_tables.end()) {
1298                ProduceTableForwardDeclaration(iter->second);
1299            }
1300            break;
1301        }
1302        case flat::Decl::Kind::kUnion: {
1303            auto iter = named_unions.find(decl);
1304            if (iter != named_unions.end()) {
1305                ProduceUnionForwardDeclaration(iter->second);
1306            }
1307            break;
1308        }
1309        default:
1310            abort();
1311        }
1312    }
1313
1314    file_ << "\n// Extern declarations\n\n";
1315
1316    for (const auto* decl : library_->declaration_order_) {
1317        switch (decl->kind) {
1318        case flat::Decl::Kind::kConst:
1319        case flat::Decl::Kind::kEnum:
1320        case flat::Decl::Kind::kStruct:
1321        case flat::Decl::Kind::kTable:
1322        case flat::Decl::Kind::kUnion:
1323            // Only messages have extern fidl_type_t declarations.
1324            break;
1325        case flat::Decl::Kind::kInterface: {
1326            auto iter = named_interfaces.find(decl);
1327            if (iter != named_interfaces.end()) {
1328                ProduceInterfaceExternDeclaration(iter->second);
1329            }
1330            break;
1331        }
1332        default:
1333            abort();
1334        }
1335    }
1336
1337    file_ << "\n// Declarations\n\n";
1338
1339    for (const auto* decl : library_->declaration_order_) {
1340        switch (decl->kind) {
1341        case flat::Decl::Kind::kConst: {
1342            auto iter = named_consts.find(decl);
1343            if (iter != named_consts.end()) {
1344                ProduceConstDeclaration(iter->second);
1345            }
1346            break;
1347        }
1348        case flat::Decl::Kind::kEnum:
1349            // Enums can be entirely forward declared, as they have no
1350            // dependencies other than standard headers.
1351            break;
1352        case flat::Decl::Kind::kInterface: {
1353            auto iter = named_interfaces.find(decl);
1354            if (iter != named_interfaces.end()) {
1355                ProduceInterfaceDeclaration(iter->second);
1356            }
1357            break;
1358        }
1359        case flat::Decl::Kind::kStruct: {
1360            auto iter = named_structs.find(decl);
1361            if (iter != named_structs.end()) {
1362                ProduceStructDeclaration(iter->second);
1363            }
1364            break;
1365        }
1366        case flat::Decl::Kind::kTable:
1367            // Tables are entirely forward declared, and their body is defined only in
1368            // implementation files.
1369            break;
1370        case flat::Decl::Kind::kUnion: {
1371            auto iter = named_unions.find(decl);
1372            if (iter != named_unions.end()) {
1373                ProduceUnionDeclaration(iter->second);
1374            }
1375            break;
1376        }
1377        default:
1378            abort();
1379        }
1380    }
1381
1382    file_ << "\n// Simple bindings \n\n";
1383
1384    for (const auto* decl : library_->declaration_order_) {
1385        switch (decl->kind) {
1386        case flat::Decl::Kind::kConst:
1387        case flat::Decl::Kind::kEnum:
1388        case flat::Decl::Kind::kStruct:
1389        case flat::Decl::Kind::kTable:
1390        case flat::Decl::Kind::kUnion:
1391            // Only interfaces have client declarations.
1392            break;
1393        case flat::Decl::Kind::kInterface: {
1394            if (!HasSimpleLayout(decl))
1395                break;
1396            auto iter = named_interfaces.find(decl);
1397            if (iter != named_interfaces.end()) {
1398                ProduceInterfaceClientDeclaration(iter->second);
1399                ProduceInterfaceServerDeclaration(iter->second);
1400            }
1401            break;
1402        }
1403        default:
1404            abort();
1405        }
1406    }
1407
1408    GenerateEpilogues();
1409
1410    return std::move(file_);
1411}
1412
1413std::ostringstream CGenerator::ProduceClient() {
1414    EmitFileComment(&file_);
1415    EmitIncludeHeader(&file_, "<lib/fidl/coding.h>");
1416    EmitIncludeHeader(&file_, "<string.h>");
1417    EmitIncludeHeader(&file_, "<zircon/syscalls.h>");
1418    EmitIncludeHeader(&file_, "<" + NameLibraryCHeader(library_->name()) + ">");
1419    EmitBlank(&file_);
1420
1421    std::map<const flat::Decl*, NamedInterface> named_interfaces =
1422        NameInterfaces(library_->interface_declarations_);
1423
1424    for (const auto* decl : library_->declaration_order_) {
1425        switch (decl->kind) {
1426        case flat::Decl::Kind::kConst:
1427        case flat::Decl::Kind::kEnum:
1428        case flat::Decl::Kind::kStruct:
1429        case flat::Decl::Kind::kTable:
1430        case flat::Decl::Kind::kUnion:
1431            // Only interfaces have client implementations.
1432            break;
1433        case flat::Decl::Kind::kInterface: {
1434            if (!HasSimpleLayout(decl))
1435                break;
1436            auto iter = named_interfaces.find(decl);
1437            if (iter != named_interfaces.end()) {
1438                ProduceInterfaceClientImplementation(iter->second);
1439            }
1440            break;
1441        }
1442        default:
1443            abort();
1444        }
1445    }
1446
1447    return std::move(file_);
1448}
1449
1450std::ostringstream CGenerator::ProduceServer() {
1451    EmitFileComment(&file_);
1452    EmitIncludeHeader(&file_, "<lib/fidl/coding.h>");
1453    EmitIncludeHeader(&file_, "<string.h>");
1454    EmitIncludeHeader(&file_, "<zircon/syscalls.h>");
1455    EmitIncludeHeader(&file_, "<" + NameLibraryCHeader(library_->name()) + ">");
1456    EmitBlank(&file_);
1457
1458    std::map<const flat::Decl*, NamedInterface> named_interfaces =
1459        NameInterfaces(library_->interface_declarations_);
1460
1461    for (const auto* decl : library_->declaration_order_) {
1462        switch (decl->kind) {
1463        case flat::Decl::Kind::kConst:
1464        case flat::Decl::Kind::kEnum:
1465        case flat::Decl::Kind::kStruct:
1466        case flat::Decl::Kind::kTable:
1467        case flat::Decl::Kind::kUnion:
1468            // Only interfaces have client implementations.
1469            break;
1470        case flat::Decl::Kind::kInterface: {
1471            if (!HasSimpleLayout(decl))
1472                break;
1473            auto iter = named_interfaces.find(decl);
1474            if (iter != named_interfaces.end()) {
1475                ProduceInterfaceServerImplementation(iter->second);
1476            }
1477            break;
1478        }
1479        default:
1480            abort();
1481        }
1482    }
1483
1484    return std::move(file_);
1485}
1486
1487} // namespace fidl
1488