serde_generate/
solidity.rs

1// Copyright (c) Facebook, Inc. and its affiliates
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use crate::{
5    indent::{IndentConfig, IndentedWriter},
6    CodeGeneratorConfig,
7};
8use heck::SnakeCase;
9use phf::phf_set;
10use serde_reflection::{ContainerFormat, Format, Named, Registry, VariantFormat};
11use std::{
12    collections::{BTreeMap, HashSet},
13    io::{Result, Write},
14    path::PathBuf,
15};
16
17/// Main configuration object for code-generation in solidity
18pub struct CodeGenerator<'a> {
19    /// Language-independent configuration.
20    config: &'a CodeGeneratorConfig,
21}
22
23/// Shared state for the code generation of a solidity source file.
24struct SolEmitter<'a, T> {
25    /// Writer.
26    out: IndentedWriter<T>,
27    /// Generator.
28    generator: &'a CodeGenerator<'a>,
29}
30
31fn get_data_location(need_memory: bool) -> String {
32    match need_memory {
33        true => " memory".to_string(),
34        false => "".to_string(),
35    }
36}
37
38fn output_generic_bcs_deserialize<T: std::io::Write>(
39    out: &mut IndentedWriter<T>,
40    key_name: &str,
41    code_name: &str,
42    need_memory: bool,
43) -> Result<()> {
44    let data_location = get_data_location(need_memory);
45    writeln!(
46        out,
47        r#"
48function bcs_deserialize_{key_name}(bytes memory input)
49    internal
50    pure
51    returns ({code_name}{data_location})
52{{
53    uint256 new_pos;
54    {code_name}{data_location} value;
55    (new_pos, value) = bcs_deserialize_offset_{key_name}(0, input);
56    require(new_pos == input.length, "incomplete deserialization");
57    return value;
58}}"#
59    )?;
60    Ok(())
61}
62
63static KEYWORDS: phf::Set<&str> = phf_set! {
64    "abstract", "after", "alias", "anonymous",
65    "as", "assembly", "break", "catch", "constant",
66    "continue", "constructor", "contract", "delete",
67    "do", "else", "emit", "enum", "error", "event",
68    "external", "fallback", "for", "function", "if",
69    "immutable", "import", "indexed", "interface",
70    "internal", "is", "library", "mapping", "memory",
71    "modifier", "new", "override", "payable", "pragma",
72    "private", "public", "pure", "receive", "return",
73    "returns", "revert", "storage", "struct", "throw",
74    "try", "type", "unchecked", "using", "virtual",
75    "view", "while", "addmod", "blockhash", "ecrecover",
76    "keccak256", "mulmod", "sha256", "ripemd160",
77    "block", "msg", "tx", "balance", "transfer", "send",
78    "call", "delegatecall", "staticcall", "this",
79    "super", "gwei", "finney", "szabo", "ether",
80    "seconds", "minutes", "hours", "days", "weeks",
81    "years", "wei", "hex", "address", "bool", "bytes",
82    "string", "int", "int8", "int16", "int32", "int64",
83    "int128", "int256", "uint", "uint8", "uint16",
84    "uint32", "uint64", "uint128", "uint256",
85    "bytes1", "bytes2", "bytes3", "bytes4", "bytes5",
86    "bytes6", "bytes7", "bytes8", "bytes9", "bytes10",
87    "bytes11", "bytes12", "bytes13", "bytes14", "bytes15",
88    "bytes16", "bytes17", "bytes18", "bytes19", "bytes20",
89    "bytes21", "bytes22", "bytes23", "bytes24", "bytes25",
90    "bytes26", "bytes27", "bytes28", "bytes29", "bytes30",
91    "bytes31", "bytes32"
92};
93
94fn safe_variable(s: &str) -> String {
95    if KEYWORDS.contains(s) {
96        s.to_owned() + "_"
97    } else {
98        s.to_string()
99    }
100}
101
102#[derive(Clone, Debug, PartialEq)]
103enum Primitive {
104    Unit,
105    Bool,
106    I8,
107    I16,
108    I32,
109    I64,
110    I128,
111    U8,
112    U16,
113    U32,
114    U64,
115    U128,
116    Char,
117    Str,
118    Bytes,
119}
120
121impl Primitive {
122    pub fn name(&self) -> String {
123        use Primitive::*;
124        match self {
125            Unit => "empty_struct".into(),
126            Bool => "bool".into(),
127            I8 => "int8".into(),
128            I16 => "int16".into(),
129            I32 => "int32".into(),
130            I64 => "int64".into(),
131            I128 => "int128".into(),
132            U8 => "uint8".into(),
133            U16 => "uint16".into(),
134            U32 => "uint32".into(),
135            U64 => "uint64".into(),
136            U128 => "uint128".into(),
137            Char => "bytes1".into(),
138            Str => "string".into(),
139            Bytes => "bytes".into(),
140        }
141    }
142
143    pub fn need_memory(&self) -> bool {
144        matches!(self, Primitive::Unit | Primitive::Bytes | Primitive::Str)
145    }
146
147    pub fn output<T: std::io::Write>(&self, out: &mut IndentedWriter<T>) -> Result<()> {
148        use Primitive::*;
149        match self {
150            Unit => writeln!(
151                out,
152                r#"
153struct empty_struct {{
154    int8 val;
155}}
156
157function bcs_serialize_empty_struct(empty_struct memory input)
158    internal
159    pure
160    returns (bytes memory)
161{{
162    bytes memory result;
163    return result;
164}}
165
166function bcs_deserialize_offset_empty_struct(uint256 pos, bytes memory input)
167    internal
168    pure
169    returns (uint256, empty_struct memory)
170{{
171    int8 val = 0;
172    return (pos, empty_struct(val));
173}}"#
174            )?,
175            Bool => {
176                writeln!(
177                    out,
178                    r#"
179function bcs_serialize_bool(bool input)
180    internal
181    pure
182    returns (bytes memory)
183{{
184    return abi.encodePacked(input);
185}}
186
187function bcs_deserialize_offset_bool(uint256 pos, bytes memory input)
188    internal
189    pure
190    returns (uint256, bool)
191{{
192    uint8 val = uint8(input[pos]);
193    bool result = false;
194    if (val == 1) {{
195        result = true;
196    }} else {{
197        require(val == 0);
198    }}
199    return (pos + 1, result);
200}}"#
201                )?;
202            }
203            I8 => {
204                writeln!(
205                    out,
206                    r#"
207function bcs_serialize_int8(int8 input)
208    internal
209    pure
210    returns (bytes memory)
211{{
212    return abi.encodePacked(input);
213}}
214
215function bcs_deserialize_offset_int8(uint256 pos, bytes memory input)
216    internal
217    pure
218    returns (uint256, int8)
219{{
220    int16 val = int16(uint16(uint8(input[pos])));
221    if (val < 128) {{
222        return (pos + 1, int8(val));
223    }} else {{
224        return (pos + 1, int8(val - 256));
225    }}
226}}"#
227                )?;
228            }
229            I16 => writeln!(
230                out,
231                r#"
232function bcs_serialize_int16(int16 input)
233    internal
234    pure
235    returns (bytes memory)
236{{
237    bytes memory result = new bytes(2);
238    uint16 uinput;
239    if (input >= 0) {{
240        uinput = uint16(input);
241    }} else {{
242        int32 input_32 = int32(input) + 65536;
243        uinput = uint16(uint32(input_32));
244    }}
245    return bcs_serialize_uint16(uinput);
246}}
247
248function bcs_deserialize_offset_int16(uint256 pos, bytes memory input)
249    internal
250    pure
251    returns (uint256, int16)
252{{
253    uint256 new_pos;
254    uint16 uresult;
255    (new_pos, uresult) = bcs_deserialize_offset_uint16(pos, input);
256    int16 result;
257    if (uresult < 32768) {{
258        result = int16(uresult);
259        return (new_pos, result);
260    }} else {{
261        int32 result_32 = int32(uint32(uresult)) - 65536;
262        result = int16(result_32);
263    }}
264    return (new_pos, result);
265}}"#
266            )?,
267            I32 => {
268                writeln!(
269                    out,
270                    r#"
271function bcs_serialize_int32(int32 input)
272    internal
273    pure
274    returns (bytes memory)
275{{
276    bytes memory result = new bytes(4);
277    uint32 uinput;
278    if (input >= 0) {{
279        uinput = uint32(input);
280    }} else {{
281        int64 input_64 = int64(input) + 4294967296;
282        uinput = uint32(uint64(input_64));
283    }}
284    return bcs_serialize_uint32(uinput);
285}}
286
287function bcs_deserialize_offset_int32(uint256 pos, bytes memory input)
288    internal
289    pure
290    returns (uint256, int32)
291{{
292    uint256 new_pos;
293    uint32 uresult;
294    (new_pos, uresult) = bcs_deserialize_offset_uint32(pos, input);
295    int32 result;
296    if (uresult < 2147483648) {{
297        result = int32(uresult);
298        return (new_pos, result);
299    }} else {{
300        int64 result_64 = int64(uint64(uresult)) - 4294967296;
301        result = int32(result_64);
302    }}
303    return (new_pos, result);
304}}"#
305                )?;
306            }
307            I64 => {
308                writeln!(
309                    out,
310                    r#"
311function bcs_serialize_int64(int64 input)
312    internal
313    pure
314    returns (bytes memory)
315{{
316    bytes memory result = new bytes(8);
317    uint64 uinput;
318    if (input >= 0) {{
319        uinput = uint64(input);
320    }} else {{
321        int128 input_128 = int128(input) + 18446744073709551616;
322        uinput = uint64(uint128(input_128));
323    }}
324    return bcs_serialize_uint64(uinput);
325}}
326
327function bcs_deserialize_offset_int64(uint256 pos, bytes memory input)
328    internal
329    pure
330    returns (uint256, int64)
331{{
332    uint256 new_pos;
333    uint64 uresult;
334    (new_pos, uresult) = bcs_deserialize_offset_uint64(pos, input);
335    int64 result;
336    if (uresult < 9223372036854775808) {{
337        result = int64(uresult);
338        return (new_pos, result);
339    }} else {{
340        int128 result_128 = int128(uint128(uresult)) - 18446744073709551616;
341        result = int64(result_128);
342    }}
343    return (new_pos, result);
344}}"#
345                )?;
346            }
347            I128 => {
348                writeln!(
349                    out,
350                    r#"
351function bcs_serialize_int128(int128 input)
352    internal
353    pure
354    returns (bytes memory)
355{{
356    bytes memory result = new bytes(16);
357    uint128 uinput;
358    if (input >= 0) {{
359        uinput = uint128(input);
360    }} else {{
361        int256 input_256 = int256(input) + 340282366920938463463374607431768211456;
362        uinput = uint128(uint256(input_256));
363    }}
364    return bcs_serialize_uint128(uinput);
365}}
366
367function bcs_deserialize_offset_int128(uint256 pos, bytes memory input)
368    internal
369    pure
370    returns (uint256, int128)
371{{
372    uint256 new_pos;
373    uint128 uresult;
374    (new_pos, uresult) = bcs_deserialize_offset_uint128(pos, input);
375    int128 result;
376    if (uresult < 170141183460469231731687303715884105728) {{
377        result = int128(uresult);
378        return (new_pos, result);
379    }} else {{
380        int256 result_256 = int256(uint256(uresult)) - 340282366920938463463374607431768211456;
381        result = int128(result_256);
382    }}
383    return (new_pos, result);
384}}"#
385                )?;
386            }
387            U8 => {
388                writeln!(
389                    out,
390                    r#"
391function bcs_serialize_uint8(uint8 input)
392    internal
393    pure
394    returns (bytes memory)
395{{
396  return abi.encodePacked(input);
397}}
398
399function bcs_deserialize_offset_uint8(uint256 pos, bytes memory input)
400    internal
401    pure
402    returns (uint256, uint8)
403{{
404    uint8 value = uint8(input[pos]);
405    return (pos + 1, value);
406}}"#
407                )?;
408            }
409            U16 => {
410                writeln!(
411                    out,
412                    r#"
413function bcs_serialize_uint16(uint16 input)
414    internal
415    pure
416    returns (bytes memory)
417{{
418    bytes memory result = new bytes(2);
419    uint16 value = input;
420    result[0] = bytes1(uint8(value));
421    value = value >> 8;
422    result[1] = bytes1(uint8(value));
423    return result;
424}}
425
426function bcs_deserialize_offset_uint16(uint256 pos, bytes memory input)
427    internal
428    pure
429    returns (uint256, uint16)
430{{
431    uint16 value = uint8(input[pos+1]);
432    value = value << 8;
433    value += uint8(input[pos]);
434    return (pos + 2, value);
435}}"#
436                )?;
437            }
438            U32 => {
439                writeln!(
440                    out,
441                    r#"
442function bcs_serialize_uint32(uint32 input)
443    internal
444    pure
445    returns (bytes memory)
446{{
447    bytes memory result = new bytes(4);
448    uint32 value = input;
449    result[0] = bytes1(uint8(value));
450    for (uint i=1; i<4; i++) {{
451        value = value >> 8;
452        result[i] = bytes1(uint8(value));
453    }}
454    return result;
455}}
456
457function bcs_deserialize_offset_uint32(uint256 pos, bytes memory input)
458    internal
459    pure
460    returns (uint256, uint32)
461{{
462    uint32 value = uint8(input[pos + 3]);
463    for (uint256 i=0; i<3; i++) {{
464        value = value << 8;
465        value += uint8(input[pos + 2 - i]);
466    }}
467    return (pos + 4, value);
468}}"#
469                )?;
470            }
471            U64 => {
472                writeln!(
473                    out,
474                    r#"
475function bcs_serialize_uint64(uint64 input)
476    internal
477    pure
478    returns (bytes memory)
479{{
480    bytes memory result = new bytes(8);
481    uint64 value = input;
482    result[0] = bytes1(uint8(value));
483    for (uint i=1; i<8; i++) {{
484        value = value >> 8;
485        result[i] = bytes1(uint8(value));
486    }}
487    return result;
488}}
489
490function bcs_deserialize_offset_uint64(uint256 pos, bytes memory input)
491    internal
492    pure
493    returns (uint256, uint64)
494{{
495    uint64 value = uint8(input[pos + 7]);
496    for (uint256 i=0; i<7; i++) {{
497        value = value << 8;
498        value += uint8(input[pos + 6 - i]);
499    }}
500    return (pos + 8, value);
501}}"#
502                )?;
503            }
504            U128 => {
505                writeln!(
506                    out,
507                    r#"
508function bcs_serialize_uint128(uint128 input)
509    internal
510    pure
511    returns (bytes memory)
512{{
513    bytes memory result = new bytes(16);
514    uint128 value = input;
515    result[0] = bytes1(uint8(value));
516    for (uint i=1; i<16; i++) {{
517        value = value >> 8;
518        result[i] = bytes1(uint8(value));
519    }}
520    return result;
521}}
522
523function bcs_deserialize_offset_uint128(uint256 pos, bytes memory input)
524    internal
525    pure
526    returns (uint256, uint128)
527{{
528    uint128 value = uint8(input[pos + 15]);
529    for (uint256 i=0; i<15; i++) {{
530        value = value << 8;
531        value += uint8(input[pos + 14 - i]);
532    }}
533    return (pos + 16, value);
534}}"#
535                )?;
536            }
537            Char => {
538                writeln!(
539                    out,
540                    r#"
541function bcs_serialize_bytes1(bytes1 input)
542    internal
543    pure
544    returns (bytes memory)
545{{
546    return abi.encodePacked(input);
547}}
548
549function bcs_deserialize_offset_bytes1(uint256 pos, bytes memory input)
550    internal
551    pure
552    returns (uint256, bytes1)
553{{
554    bytes1 result = bytes1(input[pos]);
555    return (pos + 1, result);
556}}"#
557                )?;
558            }
559            Str => {
560                writeln!(
561                    out,
562                    r#"
563function bcs_serialize_string(string memory input)
564    internal
565    pure
566    returns (bytes memory)
567{{
568    bytes memory input_bytes = bytes(input);
569    uint256 number_bytes = input_bytes.length;
570    uint256 number_char = 0;
571    uint256 pos = 0;
572    while (true) {{
573        if (uint8(input_bytes[pos]) < 128) {{
574            number_char += 1;
575        }}
576        pos += 1;
577        if (pos == number_bytes) {{
578            break;
579        }}
580    }}
581    bytes memory result_len = bcs_serialize_len(number_char);
582    return abi.encodePacked(result_len, input);
583}}
584
585function bcs_deserialize_offset_string(uint256 pos, bytes memory input)
586    internal
587    pure
588    returns (uint256, string memory)
589{{
590    uint256 len;
591    uint256 new_pos;
592    (new_pos, len) = bcs_deserialize_offset_len(pos, input);
593    uint256 shift = 0;
594    for (uint256 i=0; i<len; i++) {{
595        while (true) {{
596            bytes1 val = input[new_pos + shift];
597            shift += 1;
598            if (uint8(val) < 128) {{
599                break;
600            }}
601        }}
602    }}
603    bytes memory result_bytes = new bytes(shift);
604    for (uint256 i=0; i<shift; i++) {{
605        result_bytes[i] = input[new_pos + i];
606    }}
607    string memory result = string(result_bytes);
608    return (new_pos + shift, result);
609}}
610"#
611                )?;
612            }
613            Bytes => {
614                writeln!(
615                    out,
616                    r#"
617function bcs_serialize_bytes(bytes memory input)
618    internal
619    pure
620    returns (bytes memory)
621{{
622    uint256 len = input.length;
623    bytes memory result = bcs_serialize_len(len);
624    return abi.encodePacked(result, input);
625}}
626
627function bcs_deserialize_offset_bytes(uint256 pos, bytes memory input)
628    internal
629    pure
630    returns (uint256, bytes memory)
631{{
632    uint256 len;
633    uint256 new_pos;
634    (new_pos, len) = bcs_deserialize_offset_len(pos, input);
635    bytes memory result = new bytes(len);
636    for (uint256 u=0; u<len; u++) {{
637        result[u] = input[new_pos + u];
638    }}
639    return (new_pos + len, result);
640}}"#
641                )?;
642            }
643        }
644        Ok(())
645    }
646}
647
648#[derive(Clone, Debug, PartialEq)]
649enum SolFormat {
650    /// One of the primitive types defined elsewhere
651    Primitive(Primitive),
652    /// A type defined here or elsewhere.
653    TypeName(String),
654    /// A sequence of objects.
655    Seq(Box<SolFormat>),
656    /// A simple solidity enum
657    SimpleEnum { name: String, names: Vec<String> },
658    /// A solidity struct. Used also to encapsulates Map and Tuple
659    Struct {
660        name: String,
661        formats: Vec<Named<SolFormat>>,
662    },
663    /// An option encapsulated as a solidity struct.
664    Option(Box<SolFormat>),
665    /// A Tuplearray encapsulated as a solidity struct.
666    TupleArray { format: Box<SolFormat>, size: usize },
667    /// A complex enum encapsulated as a solidity struct.
668    Enum {
669        name: String,
670        formats: Vec<Named<Option<SolFormat>>>,
671    },
672    /// A Tuplearray of N U8 has the native type bytesN
673    BytesN { size: usize },
674    /// An option of boolean
675    OptionBool,
676}
677
678impl SolFormat {
679    pub fn code_name(&self) -> String {
680        use SolFormat::*;
681        if let Seq(format) = self {
682            return format!("{}[]", format.code_name());
683        }
684        self.key_name()
685    }
686
687    pub fn key_name(&self) -> String {
688        use SolFormat::*;
689        match self {
690            Primitive(primitive) => primitive.name(),
691            TypeName(name) => name.to_string(),
692            Option(format) => format!("opt_{}", format.key_name()),
693            Seq(format) => format!("seq_{}", format.key_name()),
694            TupleArray { format, size } => format!("tuplearray{}_{}", size, format.key_name()),
695            Struct { name, formats: _ } => name.to_string(),
696            SimpleEnum { name, names: _ } => name.to_string(),
697            Enum { name, formats: _ } => name.to_string(),
698            BytesN { size } => format!("bytes{size}"),
699            OptionBool => "OptionBool".to_string(),
700        }
701    }
702
703    pub fn output<T: std::io::Write>(
704        &self,
705        out: &mut IndentedWriter<T>,
706        sol_registry: &SolRegistry,
707    ) -> Result<()> {
708        use SolFormat::*;
709        match self {
710            Primitive(primitive) => {
711                primitive.output(out)?;
712                let full_name = primitive.name();
713                let need_memory = primitive.need_memory();
714                output_generic_bcs_deserialize(out, &full_name, &full_name, need_memory)?;
715            }
716            TypeName(_) => {
717                // by definition for TypeName the code already exists
718            }
719            Option(format) => {
720                let key_name = format.key_name();
721                let code_name = format.code_name();
722                let full_name = format!("opt_{}", key_name);
723                let data_location = sol_registry.data_location(format);
724                writeln!(
725                    out,
726                    r#"
727struct {full_name} {{
728    bool has_value;
729    {code_name} value;
730}}
731
732function bcs_serialize_{full_name}({full_name} memory input)
733    internal
734    pure
735    returns (bytes memory)
736{{
737    if (input.has_value) {{
738        return abi.encodePacked(uint8(1), bcs_serialize_{key_name}(input.value));
739    }} else {{
740        return abi.encodePacked(uint8(0));
741    }}
742}}
743
744function bcs_deserialize_offset_{full_name}(uint256 pos, bytes memory input)
745    internal
746    pure
747    returns (uint256, {full_name} memory)
748{{
749    uint256 new_pos;
750    bool has_value;
751    (new_pos, has_value) = bcs_deserialize_offset_bool(pos, input);
752    {code_name}{data_location} value;
753    if (has_value) {{
754        (new_pos, value) = bcs_deserialize_offset_{key_name}(new_pos, input);
755    }}
756    return (new_pos, {full_name}(has_value, value));
757}}"#
758                )?;
759                output_generic_bcs_deserialize(out, &full_name, &full_name, true)?;
760            }
761            Seq(format) => {
762                let inner_key_name = format.key_name();
763                let inner_code_name = format.code_name();
764                let code_name = format!("{}[]", format.code_name());
765                let key_name = format!("seq_{}", format.key_name());
766                let data_location = sol_registry.data_location(format);
767                writeln!(
768                    out,
769                    r#"
770function bcs_serialize_{key_name}({code_name} memory input)
771    internal
772    pure
773    returns (bytes memory)
774{{
775    uint256 len = input.length;
776    bytes memory result = bcs_serialize_len(len);
777    for (uint256 i=0; i<len; i++) {{
778        result = abi.encodePacked(result, bcs_serialize_{inner_key_name}(input[i]));
779    }}
780    return result;
781}}
782
783function bcs_deserialize_offset_{key_name}(uint256 pos, bytes memory input)
784    internal
785    pure
786    returns (uint256, {code_name} memory)
787{{
788    uint256 len;
789    uint256 new_pos;
790    (new_pos, len) = bcs_deserialize_offset_len(pos, input);
791    {inner_code_name}[] memory result;
792    result = new {inner_code_name}[](len);
793    {inner_code_name}{data_location} value;
794    for (uint256 i=0; i<len; i++) {{
795        (new_pos, value) = bcs_deserialize_offset_{inner_key_name}(new_pos, input);
796        result[i] = value;
797    }}
798    return (new_pos, result);
799}}"#
800                )?;
801                output_generic_bcs_deserialize(out, &key_name, &code_name, true)?;
802            }
803            TupleArray { format, size } => {
804                let inner_key_name = format.key_name();
805                let inner_code_name = format.code_name();
806                let struct_name = format!("tuplearray{}_{}", size, inner_key_name);
807                writeln!(
808                    out,
809                    r#"
810struct {struct_name} {{
811    {inner_code_name}[] values;
812}}
813
814function bcs_serialize_{struct_name}({struct_name} memory input)
815    internal
816    pure
817    returns (bytes memory)
818{{
819    bytes memory result;
820    for (uint i=0; i<{size}; i++) {{
821        result = abi.encodePacked(result, bcs_serialize_{inner_key_name}(input.values[i]));
822    }}
823    return result;
824}}
825
826function bcs_deserialize_offset_{struct_name}(uint256 pos, bytes memory input)
827    internal
828    pure
829    returns (uint256, {struct_name} memory)
830{{
831    uint256 new_pos = pos;
832    {inner_code_name} value;
833    {inner_code_name}[] memory values;
834    values = new {inner_code_name}[]({size});
835    for (uint i=0; i<{size}; i++) {{
836        (new_pos, value) = bcs_deserialize_offset_{inner_key_name}(new_pos, input);
837        values[i] = value;
838    }}
839    return (new_pos, {struct_name}(values));
840}}"#
841                )?;
842                output_generic_bcs_deserialize(out, &struct_name, &struct_name, true)?;
843            }
844            Struct { name, formats } => {
845                writeln!(out)?;
846                writeln!(out, "struct {name} {{")?;
847                for named_format in formats {
848                    writeln!(
849                        out,
850                        "    {} {};",
851                        named_format.value.code_name(),
852                        safe_variable(&named_format.name)
853                    )?;
854                }
855                writeln!(
856                    out,
857                    r#"}}
858
859function bcs_serialize_{name}({name} memory input)
860    internal
861    pure
862    returns (bytes memory)
863{{"#
864                )?;
865                for (index, named_format) in formats.iter().enumerate() {
866                    let key_name = named_format.value.key_name();
867                    let safe_name = safe_variable(&named_format.name);
868                    let block = format!("bcs_serialize_{key_name}(input.{safe_name})");
869                    let block = if formats.len() > 1 {
870                        if index == 0 {
871                            format!("bytes memory result = {block}")
872                        } else if index < formats.len() - 1 {
873                            format!("result = abi.encodePacked(result, {block})")
874                        } else {
875                            format!("return abi.encodePacked(result, {block})")
876                        }
877                    } else {
878                        format!("return {block}")
879                    };
880                    writeln!(out, "    {block};")?;
881                }
882                writeln!(
883                    out,
884                    r#"}}
885
886function bcs_deserialize_offset_{name}(uint256 pos, bytes memory input)
887    internal
888    pure
889    returns (uint256, {name} memory)
890{{
891    uint256 new_pos;"#
892                )?;
893                for (index, named_format) in formats.iter().enumerate() {
894                    let data_location = sol_registry.data_location(&named_format.value);
895                    let code_name = named_format.value.code_name();
896                    let key_name = named_format.value.key_name();
897                    let safe_name = safe_variable(&named_format.name);
898                    let start_pos = if index == 0 { "pos" } else { "new_pos" };
899                    writeln!(out, "    {code_name}{data_location} {safe_name};")?;
900                    writeln!(out, "    (new_pos, {safe_name}) = bcs_deserialize_offset_{key_name}({start_pos}, input);")?;
901                }
902                writeln!(
903                    out,
904                    "    return (new_pos, {name}({}));",
905                    formats
906                        .iter()
907                        .map(|named_format| safe_variable(&named_format.name))
908                        .collect::<Vec<_>>()
909                        .join(", ")
910                )?;
911                writeln!(out, "}}")?;
912                output_generic_bcs_deserialize(out, name, name, true)?;
913            }
914            SimpleEnum { name, names } => {
915                let names_join = names.join(", ");
916                let number_names = names.len();
917                writeln!(
918                    out,
919                    r#"
920enum {name} {{ {names_join} }}
921
922function bcs_serialize_{name}({name} input)
923    internal
924    pure
925    returns (bytes memory)
926{{
927    return abi.encodePacked(input);
928}}
929
930function bcs_deserialize_offset_{name}(uint256 pos, bytes memory input)
931    internal
932    pure
933    returns (uint256, {name})
934{{
935    uint8 choice = uint8(input[pos]);"#
936                )?;
937                for (idx, name_choice) in names.iter().enumerate() {
938                    writeln!(
939                        out,
940                        r#"
941    if (choice == {idx}) {{
942        return (pos + 1, {name}.{name_choice});
943    }}"#
944                    )?;
945                }
946                writeln!(
947                    out,
948                    r#"
949    require(choice < {number_names});
950}}"#
951                )?;
952                output_generic_bcs_deserialize(out, name, name, false)?;
953            }
954            Enum { name, formats } => {
955                let number_names = formats.len();
956                writeln!(
957                    out,
958                    r#"
959struct {name} {{
960    uint8 choice;"#
961                )?;
962                for (idx, named_format) in formats.iter().enumerate() {
963                    let name = named_format.name.clone();
964                    writeln!(out, "    // choice={idx} corresponds to {name}")?;
965                    if let Some(format) = &named_format.value {
966                        let code_name = format.code_name();
967                        let snake_name = safe_variable(&named_format.name.to_snake_case());
968                        writeln!(out, "    {code_name} {snake_name};")?;
969                    }
970                }
971                writeln!(out, "}}")?;
972                let mut entries = Vec::new();
973                let mut type_vars = Vec::new();
974                for named_format in formats {
975                    if let Some(format) = &named_format.value {
976                        let data_location = sol_registry.data_location(format);
977                        let snake_name = safe_variable(&named_format.name.to_snake_case());
978                        let code_name = format.code_name();
979                        let type_var = format!("{code_name}{data_location} {snake_name}");
980                        type_vars.push(type_var);
981                        entries.push(snake_name);
982                    } else {
983                        type_vars.push(String::new());
984                    }
985                }
986                let entries = entries.join(", ");
987                for (choice, named_format_i) in formats.iter().enumerate() {
988                    let snake_name = named_format_i.name.to_snake_case();
989                    let type_var = &type_vars[choice];
990                    writeln!(
991                        out,
992                        r#"
993function {name}_case_{snake_name}({type_var})
994    internal
995    pure
996    returns ({name} memory)
997{{"#
998                    )?;
999                    for (i_choice, type_var) in type_vars.iter().enumerate() {
1000                        if !type_var.is_empty() && choice != i_choice {
1001                            writeln!(out, "    {type_var};")?;
1002                        }
1003                    }
1004                    writeln!(out, "    return {name}(uint8({choice}), {entries});")?;
1005                    writeln!(out, "}}")?;
1006                }
1007                writeln!(
1008                    out,
1009                    r#"
1010function bcs_serialize_{name}({name} memory input)
1011    internal
1012    pure
1013    returns (bytes memory)
1014{{"#
1015                )?;
1016                for (idx, named_format) in formats.iter().enumerate() {
1017                    if let Some(format) = &named_format.value {
1018                        let key_name = format.key_name();
1019                        let snake_name = safe_variable(&named_format.name.to_snake_case());
1020                        writeln!(out, "    if (input.choice == {idx}) {{")?;
1021                        writeln!(out, "        return abi.encodePacked(input.choice, bcs_serialize_{key_name}(input.{snake_name}));")?;
1022                        writeln!(out, "    }}")?;
1023                    }
1024                }
1025                writeln!(
1026                    out,
1027                    r#"    return abi.encodePacked(input.choice);
1028}}
1029
1030function bcs_deserialize_offset_{name}(uint256 pos, bytes memory input)
1031    internal
1032    pure
1033    returns (uint256, {name} memory)
1034{{
1035    uint256 new_pos;
1036    uint8 choice;
1037    (new_pos, choice) = bcs_deserialize_offset_uint8(pos, input);"#
1038                )?;
1039                let mut entries = Vec::new();
1040                for (idx, named_format) in formats.iter().enumerate() {
1041                    if let Some(format) = &named_format.value {
1042                        let data_location = sol_registry.data_location(format);
1043                        let snake_name = safe_variable(&named_format.name.to_snake_case());
1044                        let code_name = format.code_name();
1045                        let key_name = format.key_name();
1046                        writeln!(out, "    {code_name}{data_location} {snake_name};")?;
1047                        writeln!(out, "    if (choice == {idx}) {{")?;
1048                        writeln!(out, "        (new_pos, {snake_name}) = bcs_deserialize_offset_{key_name}(new_pos, input);")?;
1049                        writeln!(out, "    }}")?;
1050                        entries.push(snake_name);
1051                    }
1052                }
1053                writeln!(out, "    require(choice < {number_names});")?;
1054                let entries = entries.join(", ");
1055                writeln!(
1056                    out,
1057                    r#"    return (new_pos, {name}(choice, {entries}));
1058}}"#
1059                )?;
1060                output_generic_bcs_deserialize(out, name, name, true)?;
1061            }
1062            BytesN { size } => {
1063                let name = format!("bytes{size}");
1064                writeln!(
1065                    out,
1066                    r#"
1067function bcs_serialize_{name}({name} input)
1068    internal
1069    pure
1070    returns (bytes memory)
1071{{
1072    return abi.encodePacked(input);
1073}}
1074
1075function bcs_deserialize_offset_{name}(uint256 pos, bytes memory input)
1076    internal
1077    pure
1078    returns (uint256, {name})
1079{{
1080    {name} dest;
1081    assembly {{
1082        dest := mload(add(add(input, 0x20), pos))
1083    }}
1084    return (pos + {size}, dest);
1085}}"#
1086                )?;
1087            }
1088            OptionBool => {
1089                let name = "OptionBool";
1090                writeln!(
1091                    out,
1092                    r#"
1093enum {name} {{ None, True, False }}
1094
1095function bcs_serialize_{name}({name} input)
1096    internal
1097    pure
1098    returns (bytes memory)
1099{{
1100    if (input == {name}.None) {{
1101        return abi.encodePacked(uint8(0));
1102    }}
1103    if (input == {name}.False) {{
1104        return abi.encodePacked(uint8(1), uint8(0));
1105    }}
1106    return abi.encodePacked(uint8(1), uint8(1));
1107}}
1108
1109function bcs_deserialize_offset_{name}(uint256 pos, bytes memory input)
1110    internal
1111    pure
1112    returns (uint256, {name})
1113{{
1114    uint8 choice = uint8(input[pos]);
1115    if (choice == 0) {{
1116       return (pos + 1, {name}.None);
1117    }} else {{
1118        require(choice == 1);
1119        uint8 value = uint8(input[pos + 1]);
1120        if (value == 0) {{
1121            return (pos + 2, {name}.False);
1122        }} else {{
1123            require(value == 1);
1124            return (pos + 2, {name}.True);
1125        }}
1126    }}
1127}}"#
1128                )?;
1129                output_generic_bcs_deserialize(out, name, name, false)?;
1130            }
1131        }
1132        Ok(())
1133    }
1134
1135    fn get_dependency(&self) -> Vec<String> {
1136        use SolFormat::*;
1137        match self {
1138            Primitive(_) => vec![],
1139            TypeName(name) => vec![name.to_string()],
1140            Seq(format) => vec![format.key_name()],
1141            SimpleEnum { name: _, names: _ } => vec![],
1142            Struct { name: _, formats } => formats
1143                .iter()
1144                .map(|format| format.value.key_name())
1145                .collect(),
1146            Option(format) => vec![format.key_name()],
1147            TupleArray { format, size: _ } => vec![format.key_name()],
1148            Enum { name: _, formats } => formats
1149                .iter()
1150                .flat_map(|format| match &format.value {
1151                    None => vec![],
1152                    Some(format) => vec![format.key_name()],
1153                })
1154                .collect(),
1155            BytesN { size: _ } => vec![],
1156            OptionBool => vec![],
1157        }
1158    }
1159}
1160
1161#[derive(Default)]
1162struct SolRegistry {
1163    names: BTreeMap<String, SolFormat>,
1164}
1165
1166impl SolRegistry {
1167    fn insert(&mut self, sol_format: SolFormat) {
1168        let key_name = sol_format.key_name();
1169        // If we insert the signed version, then we also need the unsigned one internally
1170        match sol_format {
1171            SolFormat::Primitive(Primitive::I8) => {
1172                self.names.insert(key_name, sol_format);
1173                self.names
1174                    .insert("uint8".to_string(), SolFormat::Primitive(Primitive::U8));
1175            }
1176            SolFormat::Primitive(Primitive::I16) => {
1177                self.names.insert(key_name, sol_format);
1178                self.names
1179                    .insert("uint16".to_string(), SolFormat::Primitive(Primitive::U16));
1180            }
1181            SolFormat::Primitive(Primitive::I32) => {
1182                self.names.insert(key_name, sol_format);
1183                self.names
1184                    .insert("uint32".to_string(), SolFormat::Primitive(Primitive::U32));
1185            }
1186            SolFormat::Primitive(Primitive::I64) => {
1187                self.names.insert(key_name, sol_format);
1188                self.names
1189                    .insert("uint64".to_string(), SolFormat::Primitive(Primitive::U64));
1190            }
1191            SolFormat::Primitive(Primitive::I128) => {
1192                self.names.insert(key_name, sol_format);
1193                self.names
1194                    .insert("uint128".to_string(), SolFormat::Primitive(Primitive::U128));
1195            }
1196            SolFormat::TypeName(_) => {
1197                // Typename entries do not need to be inserted.
1198            }
1199            _ => {
1200                self.names.insert(key_name, sol_format);
1201            }
1202        }
1203    }
1204
1205    fn has_circular_dependency(&self) -> bool {
1206        for start_key in self.names.keys() {
1207            let mut level = HashSet::<String>::new();
1208            level.insert(start_key.to_string());
1209            let mut total_dependency = level.clone();
1210            loop {
1211                let mut new_level = HashSet::new();
1212                for key in level {
1213                    for depend in self.names.get(&key).unwrap().get_dependency() {
1214                        if depend == *start_key {
1215                            return true;
1216                        }
1217                        if !total_dependency.contains(&depend) {
1218                            total_dependency.insert(depend.clone());
1219                            new_level.insert(depend);
1220                        }
1221                    }
1222                }
1223                if new_level.is_empty() {
1224                    break;
1225                }
1226                level = new_level;
1227            }
1228        }
1229        false
1230    }
1231
1232    fn parse_format(&mut self, format: Format) -> SolFormat {
1233        use Format::*;
1234        let sol_format = match format {
1235            Variable(_) => panic!("variable is not supported in solidity"),
1236            TypeName(name) => SolFormat::TypeName(name),
1237            Unit => SolFormat::Primitive(Primitive::Unit),
1238            Bool => SolFormat::Primitive(Primitive::Bool),
1239            I8 => SolFormat::Primitive(Primitive::I8),
1240            I16 => SolFormat::Primitive(Primitive::I16),
1241            I32 => SolFormat::Primitive(Primitive::I32),
1242            I64 => SolFormat::Primitive(Primitive::I64),
1243            I128 => SolFormat::Primitive(Primitive::I128),
1244            U8 => SolFormat::Primitive(Primitive::U8),
1245            U16 => SolFormat::Primitive(Primitive::U16),
1246            U32 => SolFormat::Primitive(Primitive::U32),
1247            U64 => SolFormat::Primitive(Primitive::U64),
1248            U128 => SolFormat::Primitive(Primitive::U128),
1249            F32 => panic!("floating point is not supported in solidity"),
1250            F64 => panic!("floating point is not supported in solidity"),
1251            Char => SolFormat::Primitive(Primitive::Char),
1252            Str => SolFormat::Primitive(Primitive::Str),
1253            Bytes => SolFormat::Primitive(Primitive::Bytes),
1254            Option(format) => {
1255                let format = self.parse_format(*format);
1256                if format == SolFormat::Primitive(Primitive::Bool) {
1257                    SolFormat::OptionBool
1258                } else {
1259                    SolFormat::Option(Box::new(format))
1260                }
1261            }
1262            Seq(format) => {
1263                let format = self.parse_format(*format);
1264                SolFormat::Seq(Box::new(format))
1265            }
1266            Map { key, value } => {
1267                let key = self.parse_format(*key);
1268                let value = self.parse_format(*value);
1269                let name = format!("key_values_{}_{}", key.key_name(), value.key_name());
1270                let formats = vec![
1271                    Named {
1272                        name: "key".into(),
1273                        value: key,
1274                    },
1275                    Named {
1276                        name: "value".into(),
1277                        value,
1278                    },
1279                ];
1280                let sol_format = SolFormat::Struct { name, formats };
1281                self.insert(sol_format.clone());
1282                SolFormat::Seq(Box::new(sol_format))
1283            }
1284            Tuple(formats) => {
1285                let formats = formats
1286                    .into_iter()
1287                    .map(|format| self.parse_format(format))
1288                    .collect::<Vec<_>>();
1289                let name = format!(
1290                    "tuple_{}",
1291                    formats
1292                        .iter()
1293                        .map(|format| format.key_name())
1294                        .collect::<Vec<_>>()
1295                        .join("_")
1296                );
1297                let formats = formats
1298                    .into_iter()
1299                    .enumerate()
1300                    .map(|(idx, format)| Named {
1301                        name: format!("entry{idx}"),
1302                        value: format,
1303                    })
1304                    .collect();
1305                SolFormat::Struct { name, formats }
1306            }
1307            TupleArray { content, size } => {
1308                let format = self.parse_format(*content);
1309                if (1..=32).contains(&size) && format == SolFormat::Primitive(Primitive::U8) {
1310                    SolFormat::BytesN { size }
1311                } else {
1312                    SolFormat::TupleArray {
1313                        format: Box::new(format),
1314                        size,
1315                    }
1316                }
1317            }
1318        };
1319        self.insert(sol_format.clone());
1320        sol_format
1321    }
1322
1323    fn parse_struct_format(&mut self, name: String, formats: Vec<Named<Format>>) -> SolFormat {
1324        let formats = formats
1325            .into_iter()
1326            .map(|named_format| Named {
1327                name: named_format.name,
1328                value: self.parse_format(named_format.value),
1329            })
1330            .collect();
1331        let sol_format = SolFormat::Struct { name, formats };
1332        self.insert(sol_format.clone());
1333        sol_format
1334    }
1335
1336    fn parse_container_format(&mut self, container_format: Named<ContainerFormat>) {
1337        use ContainerFormat::*;
1338        let name = container_format.name;
1339        let sol_format = match container_format.value {
1340            UnitStruct => panic!("UnitStruct is not supported in solidity"),
1341            NewTypeStruct(format) => {
1342                let format = Named {
1343                    name: "value".to_string(),
1344                    value: *format,
1345                };
1346                let formats = vec![format];
1347                self.parse_struct_format(name, formats)
1348            }
1349            TupleStruct(formats) => {
1350                assert!(
1351                    !formats.is_empty(),
1352                    "The TupleStruct should be non-trivial in solidity"
1353                );
1354                let formats = formats
1355                    .into_iter()
1356                    .enumerate()
1357                    .map(|(idx, value)| Named {
1358                        name: format!("entry{idx}"),
1359                        value,
1360                    })
1361                    .collect();
1362                self.parse_struct_format(name, formats)
1363            }
1364            Struct(formats) => {
1365                assert!(
1366                    !formats.is_empty(),
1367                    "The struct should be non-trivial in solidity"
1368                );
1369                self.parse_struct_format(name, formats)
1370            }
1371            Enum(map) => {
1372                assert!(
1373                    !map.is_empty(),
1374                    "The enum should be non-trivial in solidity"
1375                );
1376                assert!(map.len() < 256, "The enum should have at most 256 entries");
1377                let is_trivial = map
1378                    .iter()
1379                    .all(|(_, v)| matches!(v.value, VariantFormat::Unit));
1380                if is_trivial {
1381                    let names = map
1382                        .into_values()
1383                        .map(|named_format| named_format.name)
1384                        .collect();
1385                    SolFormat::SimpleEnum { name, names }
1386                } else {
1387                    let choice_sol_format = SolFormat::Primitive(Primitive::U8);
1388                    self.insert(choice_sol_format);
1389                    let mut formats = Vec::new();
1390                    for (_key, value) in map {
1391                        use VariantFormat::*;
1392                        let name_red = value.name;
1393                        let concat_name = format!("{}_{}", name, name_red);
1394                        let entry = match value.value {
1395                            VariantFormat::Unit => None,
1396                            NewType(format) => Some(self.parse_format(*format)),
1397                            Tuple(formats) => {
1398                                let formats = formats
1399                                    .into_iter()
1400                                    .enumerate()
1401                                    .map(|(idx, value)| Named {
1402                                        name: format!("entry{idx}"),
1403                                        value,
1404                                    })
1405                                    .collect::<Vec<_>>();
1406                                Some(self.parse_struct_format(concat_name, formats))
1407                            }
1408                            Struct(formats) => Some(self.parse_struct_format(concat_name, formats)),
1409                            Variable(_) => panic!("Variable is not supported for solidity"),
1410                        };
1411                        let format = Named {
1412                            name: name_red,
1413                            value: entry,
1414                        };
1415                        formats.push(format);
1416                    }
1417                    SolFormat::Enum { name, formats }
1418                }
1419            }
1420        };
1421        self.insert(sol_format);
1422    }
1423
1424    fn need_memory(&self, sol_format: &SolFormat) -> bool {
1425        use SolFormat::*;
1426        match sol_format {
1427            Primitive(primitive) => primitive.need_memory(),
1428            TypeName(name) => {
1429                let mesg = format!("to find a matching entry for name={name}");
1430                let sol_format = self.names.get(name).expect(&mesg);
1431                self.need_memory(sol_format)
1432            }
1433            Option(_) => true,
1434            Seq(_) => true,
1435            TupleArray { format: _, size: _ } => true,
1436            Struct {
1437                name: _,
1438                formats: _,
1439            } => true,
1440            SimpleEnum { name: _, names: _ } => false,
1441            Enum {
1442                name: _,
1443                formats: _,
1444            } => true,
1445            BytesN { size: _ } => false,
1446            OptionBool => false,
1447        }
1448    }
1449
1450    fn data_location(&self, sol_format: &SolFormat) -> String {
1451        get_data_location(self.need_memory(sol_format))
1452    }
1453}
1454
1455impl<'a> CodeGenerator<'a> {
1456    /// Create a solidity code generator for the given config.
1457    pub fn new(config: &'a CodeGeneratorConfig) -> Self {
1458        if config.c_style_enums {
1459            panic!("Solidity does not support generating c-style enums");
1460        }
1461        Self { config }
1462    }
1463
1464    pub fn output(
1465        &self,
1466        out: &mut dyn Write,
1467        registry: &Registry,
1468    ) -> std::result::Result<(), Box<dyn std::error::Error>> {
1469        let mut emitter = SolEmitter {
1470            out: IndentedWriter::new(out, IndentConfig::Space(4)),
1471            generator: self,
1472        };
1473
1474        emitter.output_license()?;
1475        emitter.output_open_library()?;
1476        emitter.output_preamble()?;
1477
1478        let mut sol_registry = SolRegistry::default();
1479        for (key, container_format) in registry {
1480            let container_format = Named {
1481                name: key.to_string(),
1482                value: container_format.clone(),
1483            };
1484            sol_registry.parse_container_format(container_format);
1485        }
1486        if sol_registry.has_circular_dependency() {
1487            panic!("solidity does not allow for circular dependencies");
1488        }
1489        for sol_format in sol_registry.names.values() {
1490            sol_format.output(&mut emitter.out, &sol_registry)?;
1491        }
1492
1493        emitter.output_close_library()?;
1494        Ok(())
1495    }
1496}
1497
1498impl<'a, T> SolEmitter<'a, T>
1499where
1500    T: std::io::Write,
1501{
1502    fn output_license(&mut self) -> Result<()> {
1503        writeln!(
1504            self.out,
1505            r#"/// SPDX-License-Identifier: UNLICENSED
1506pragma solidity ^0.8.0;"#
1507        )?;
1508        Ok(())
1509    }
1510
1511    fn output_preamble(&mut self) -> Result<()> {
1512        writeln!(
1513            self.out,
1514            r#"
1515function bcs_serialize_len(uint256 x)
1516    internal
1517    pure
1518    returns (bytes memory)
1519{{
1520    bytes memory result;
1521    bytes1 entry;
1522    while (true) {{
1523        if (x < 128) {{
1524            entry = bytes1(uint8(x));
1525            return abi.encodePacked(result, entry);
1526        }} else {{
1527            uint256 xb = x >> 7;
1528            uint256 remainder = x - (xb << 7);
1529            require(remainder < 128);
1530            entry = bytes1(uint8(remainder) + 128);
1531            result = abi.encodePacked(result, entry);
1532            x = xb;
1533        }}
1534    }}
1535    require(false, "This line is unreachable");
1536    return result;
1537}}
1538
1539function bcs_deserialize_offset_len(uint256 pos, bytes memory input)
1540    internal
1541    pure
1542    returns (uint256, uint256)
1543{{
1544    uint256 idx = 0;
1545    while (true) {{
1546        if (uint8(input[pos + idx]) < 128) {{
1547            uint256 result = 0;
1548            uint256 power = 1;
1549            for (uint256 u=0; u<idx; u++) {{
1550                uint8 val = uint8(input[pos + u]) - 128;
1551                result += power * uint256(val);
1552                power *= 128;
1553            }}
1554            result += power * uint8(input[pos + idx]);
1555            return (pos + idx + 1, result);
1556        }}
1557        idx += 1;
1558    }}
1559    require(false, "This line is unreachable");
1560    return (0,0);
1561}}"#
1562        )?;
1563        Ok(())
1564    }
1565
1566    fn output_open_library(&mut self) -> Result<()> {
1567        writeln!(
1568            self.out,
1569            "\nlibrary {} {{",
1570            self.generator.config.module_name
1571        )?;
1572        self.out.indent();
1573        Ok(())
1574    }
1575
1576    fn output_close_library(&mut self) -> Result<()> {
1577        self.out.unindent();
1578        writeln!(
1579            self.out,
1580            "\n}} // end of library {}",
1581            self.generator.config.module_name
1582        )?;
1583        Ok(())
1584    }
1585}
1586
1587/// Installer for generated source files in solidity
1588pub struct Installer {
1589    install_dir: PathBuf,
1590}
1591
1592impl Installer {
1593    pub fn new(install_dir: PathBuf) -> Self {
1594        Installer { install_dir }
1595    }
1596
1597    fn create_header_file(&self, name: &str) -> Result<std::fs::File> {
1598        let dir_path = &self.install_dir;
1599        std::fs::create_dir_all(dir_path)?;
1600        std::fs::File::create(dir_path.join(name.to_string() + ".sol"))
1601    }
1602
1603    fn runtime_installation_message(name: &str) {
1604        eprintln!("Not installing sources for published crate {}", name);
1605    }
1606}
1607
1608impl crate::SourceInstaller for Installer {
1609    type Error = Box<dyn std::error::Error>;
1610
1611    fn install_module(
1612        &self,
1613        config: &crate::CodeGeneratorConfig,
1614        registry: &Registry,
1615    ) -> std::result::Result<(), Self::Error> {
1616        let mut file = self.create_header_file(&config.module_name)?;
1617        let generator = CodeGenerator::new(config);
1618        generator.output(&mut file, registry)
1619    }
1620
1621    fn install_serde_runtime(&self) -> std::result::Result<(), Self::Error> {
1622        Self::runtime_installation_message("serde");
1623        Ok(())
1624    }
1625
1626    fn install_bincode_runtime(&self) -> std::result::Result<(), Self::Error> {
1627        Self::runtime_installation_message("bincode");
1628        Ok(())
1629    }
1630
1631    fn install_bcs_runtime(&self) -> std::result::Result<(), Self::Error> {
1632        Self::runtime_installation_message("bcs");
1633        Ok(())
1634    }
1635}