<reponame>bianjieai/solidity-protobuf
STRUCT_DEFINITION = """
  //struct definition
  struct Data {{
{fields}{map_fields}
  }}"""

ENUMS_DEFINITION = """
  //enum definition{enums}"""

MAP_FIELD_DEFINITION = """
    uint256 _size_{name};"""

UTILITY_FUNCTION = """
  //utility functions
  /**
   * @dev Return an empty struct
   * @return r The empty struct
   */
  function nil() internal pure returns ({name} memory r) {{
    assembly {{
      r := 0
    }}
  }}

  /**
   * @dev Test whether a struct is empty
   * @param x The struct to be tested
   * @return r True if it is empty
   */
  function isNil({name} memory x) internal pure returns (bool r) {{
    assembly {{
      r := iszero(x)
    }}
  }}"""

STORE_REPEATED = """
    for(uint256 i{i} = 0; i{i} < input.{field}.length; i{i}++) {{
      output.{field}.push(input.{field}[i{i}]);
    }}
    {map_insert_code}
"""

STORE_MESSAGE = "    {lib}.store(input.{field}, output.{field});\n"

STORE_OTHER = "    output.{field} = input.{field};\n"

STORE_FUNCTION = """
  //store function
  /**
   * @dev Store in-memory struct to storage
   * @param input The in-memory struct
   * @param output The in-storage struct
   */
  function store({name} memory input, {name} storage output) internal {{
{store_codes}
  }}"""

MAP_HELPER_CODE = """
  //map helpers for {name}
  /**
   * @dev Get value from a map
   * @param self The in-memory struct
   * @param key The key to get
   * @return The value in map if it exists
   */
  function get{name}(Data memory self, {key_type} {key_storage_type} key)
    internal
    pure
    returns ({value_type} {value_storage_type})
  {{
    {value_type} {value_storage_type} defaultValue;
    for (uint256 i = 0; i < {map_name}; i++) {{
      {field_type} memory data = {val_name}[i];
      if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{
        return data.value;
      }}
    }}
    return defaultValue;
  }}

  /**
   * @dev Search value from a map
   * @param self The in-memory struct
   * @param key The key to search
   * @return Whether the key exists in the map
   * @return The value in map if it exists
   */
  function search{name}(Data memory self, {key_type} {key_storage_type} key)
    internal
    pure
    returns (bool, {value_type} {value_storage_type})
  {{
    {value_type} {value_storage_type} defaultValue;
    for (uint256 i = 0; i < {map_name}; i++) {{
      {field_type} memory data = {val_name}[i];
      if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{
        return (true, data.value);
      }}
    }}
    return (false, defaultValue);
  }}

  /**
   * @dev Add key-value pair from a map
   * @param self The in-memory struct
   * @param key The key to add
   * @param value The value to add
   */
  function add{name}(Data memory self, {key_type} {key_storage_type} key, {value_type} {value_storage_type} value)
    internal
    pure
  {{
    /**
     * First search whether the key exists.
     * If not, add to the array. Otherwise, replace the value.
     * If a resize is needed, the array size will be doubled.
     */
    for (uint256 i = 0; i < {map_name}; i++) {{
      {field_type} memory data = {val_name}[i];
      if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{
        {val_name}[i].value = value;
        return;
      }}
    }}
    if ({val_name}.length == 0) {{
      {val_name} = new {field_type}[](10);
    }}
    if ({map_name} == {val_name}.length) {{
      {field_type}[] memory tmp = new {field_type}[]({val_name}.length * 2);
      for (uint256 i = 0; i < {map_name}; i++) {{
        tmp[i] = {val_name}[i];
      }}
      {val_name} = tmp;
    }}
    {field_type} memory entry;
    entry.key = key;
    entry.value = value;
    {val_name}[{map_name}++] = entry;
  }}

  /**
   * @dev Delete key from a map
   * @param self The in-memory struct
   * @param key The key to delete
   */
  function rm{name}(Data memory self, {key_type} {key_storage_type} key) internal pure {{
    /**
     * First search whether the key exists.
     * If not, do nothing.
     * Otherwise, replace with last key-value pair in the array.
     */
    uint256 pos;
    for (uint256 i = 0; i < {map_name}; i++) {{
      {field_type} memory data = {val_name}[i];
      if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{
        pos = i + 1;
        break;
      }}
    }}
    if (pos == 0) {{
      return;
    }}
    pos -= 1;
    {val_name}[pos] = {val_name}[--{map_name}];
  }}"""

ARRAY_HELPER_CODE = """
  //array helpers for {name}
  /**
   * @dev Add value to an array
   * @param self The in-memory struct
   * @param value The value to add
   */
  function add{name}(Data memory self, {field_type} {field_storage_type} value) internal pure {{
    /**
     * First resize the array. Then add the new element to the end.
     */
    {field_type}[] memory tmp = new {field_type}[]({val_name}.length + 1);
    for (uint256 i = 0; i < {val_name}.length; i++) {{
      tmp[i] = {val_name}[i];
    }}
    tmp[{val_name}.length] = value;
    {val_name} = tmp;
  }}
"""

CODECS = """
library {delegate_lib_name} {{
{enum_definition}
{struct_definition}
{decoder_section}
{encoder_section}
{store_function}
{map_helper}
{array_helper}
{utility_functions}
}}
//library {delegate_lib_name}"""

GLOBAL_ENUM_CODECS = """
library {delegate_lib_name} {{
{enum_definition}
}}
//library {delegate_lib_name}"""

STRUCT_DEFINITION = """
  //struct definition
  struct Data {{
{fields}{map_fields}
  }}"""

ENUMS_DEFINITION = """
  //enum definition{enums}"""

MAP_FIELD_DEFINITION = """
    uint256 _size_{name};"""

UTILITY_FUNCTION = """
  //utility functions
  /**
   * @dev Return an empty struct
   * @return r The empty struct
   */
  function nil() internal pure returns ({name} memory r) {{
    assembly {{
      r := 0
    }}
  }}

  /**
   * @dev Test whether a struct is empty
   * @param x The struct to be tested
   * @return r True if it is empty
   */
  function isNil({name} memory x) internal pure returns (bool r) {{
    assembly {{
      r := iszero(x)
    }}
  }}"""

STORE_REPEATED = """
    for(uint256 i{i} = 0; i{i} < input.{field}.length; i{i}++) {{
      output.{field}.push(input.{field}[i{i}]);
    }}
    {map_insert_code}
"""

STORE_MESSAGE = "    {lib}.store(input.{field}, output.{field});\n"

STORE_OTHER = "    output.{field} = input.{field};\n"

STORE_FUNCTION = """
  //store function
  /**
   * @dev Store in-memory struct to storage
   * @param input The in-memory struct
   * @param output The in-storage struct
   */
  function store({name} memory input, {name} storage output) internal {{
{store_codes}
  }}"""

MAP_HELPER_CODE = """
  //map helpers for {name}
  /**
   * @dev Get value from a map
   * @param self The in-memory struct
   * @param key The key to get
   * @return The value in map if it exists
   */
  function get{name}(Data memory self, {key_type} {key_storage_type} key)
    internal
    pure
    returns ({value_type} {value_storage_type})
  {{
    {value_type} {value_storage_type} defaultValue;
    for (uint256 i = 0; i < {map_name}; i++) {{
      {field_type} memory data = {val_name}[i];
      if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{
        return data.value;
      }}
    }}
    return defaultValue;
  }}

  /**
   * @dev Search value from a map
   * @param self The in-memory struct
   * @param key The key to search
   * @return Whether the key exists in the map
   * @return The value in map if it exists
   */
  function search{name}(Data memory self, {key_type} {key_storage_type} key)
    internal
    pure
    returns (bool, {value_type} {value_storage_type})
  {{
    {value_type} {value_storage_type} defaultValue;
    for (uint256 i = 0; i < {map_name}; i++) {{
      {field_type} memory data = {val_name}[i];
      if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{
        return (true, data.value);
      }}
    }}
    return (false, defaultValue);
  }}

  /**
   * @dev Add key-value pair from a map
   * @param self The in-memory struct
   * @param key The key to add
   * @param value The value to add
   */
  function add{name}(Data memory self, {key_type} {key_storage_type} key, {value_type} {value_storage_type} value)
    internal
    pure
  {{
    /**
     * First search whether the key exists.
     * If not, add to the array. Otherwise, replace the value.
     * If a resize is needed, the array size will be doubled.
     */
    for (uint256 i = 0; i < {map_name}; i++) {{
      {field_type} memory data = {val_name}[i];
      if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{
        {val_name}[i].value = value;
        return;
      }}
    }}
    if ({val_name}.length == 0) {{
      {val_name} = new {field_type}[](10);
    }}
    if ({map_name} == {val_name}.length) {{
      {field_type}[] memory tmp = new {field_type}[]({val_name}.length * 2);
      for (uint256 i = 0; i < {map_name}; i++) {{
        tmp[i] = {val_name}[i];
      }}
      {val_name} = tmp;
    }}
    {field_type} memory entry;
    entry.key = key;
    entry.value = value;
    {val_name}[{map_name}++] = entry;
  }}

  /**
   * @dev Delete key from a map
   * @param self The in-memory struct
   * @param key The key to delete
   */
  function rm{name}(Data memory self, {key_type} {key_storage_type} key) internal pure {{
    /**
     * First search whether the key exists.
     * If not, do nothing.
     * Otherwise, replace with last key-value pair in the array.
     */
    uint256 pos;
    for (uint256 i = 0; i < {map_name}; i++) {{
      {field_type} memory data = {val_name}[i];
      if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{
        pos = i + 1;
        break;
      }}
    }}
    if (pos == 0) {{
      return;
    }}
    pos -= 1;
    {val_name}[pos] = {val_name}[--{map_name}];
  }}"""

ARRAY_HELPER_CODE = """
  //array helpers for {name}
  /**
   * @dev Add value to an array
   * @param self The in-memory struct
   * @param value The value to add
   */
  function add{name}(Data memory self, {field_type} {field_storage_type} value) internal pure {{
    /**
     * First resize the array. Then add the new element to the end.
     */
    {field_type}[] memory tmp = new {field_type}[]({val_name}.length + 1);
    for (uint256 i = 0; i < {val_name}.length; i++) {{
      tmp[i] = {val_name}[i];
    }}
    tmp[{val_name}.length] = value;
    {val_name} = tmp;
  }}
"""

CODECS = """
library {delegate_lib_name} {{
{enum_definition}
{struct_definition}
{decoder_section}
{encoder_section}
{store_function}
{map_helper}
{array_helper}
{utility_functions}
}}
//library {delegate_lib_name}"""

GLOBAL_ENUM_CODECS = """
library {delegate_lib_name} {{
{enum_definition}
}}
//library {delegate_lib_name}"""
//struct definition   struct Data {{ {fields}{map_fields}   }} //enum definition{enums} uint256 _size_{name}; //utility functions   /**    * @dev Return an empty struct    * @return r The empty struct    */   function nil() internal pure returns ({name} memory r) {{     assembly {{       r := 0     }}   }}    /**    * @dev Test whether a struct is empty    * @param x The struct to be tested    * @return r True if it is empty    */   function isNil({name} memory x) internal pure returns (bool r) {{     assembly {{       r := iszero(x)     }}   }} for(uint256 i{i} = 0; i{i} < input.{field}.length; i{i}++) {{       output.{field}.push(input.{field}[i{i}]);     }}     {map_insert_code} //store function   /**    * @dev Store in-memory struct to storage    * @param input The in-memory struct    * @param output The in-storage struct    */   function store({name} memory input, {name} storage output) internal {{ {store_codes}   }} //map helpers for {name}   /**    * @dev Get value from a map    * @param self The in-memory struct    * @param key The key to get    * @return The value in map if it exists    */   function get{name}(Data memory self, {key_type} {key_storage_type} key)     internal     pure     returns ({value_type} {value_storage_type})   {{     {value_type} {value_storage_type} defaultValue;     for (uint256 i = 0; i < {map_name}; i++) {{       {field_type} memory data = {val_name}[i];       if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{         return data.value;       }}     }}     return defaultValue;   }}    /**    * @dev Search value from a map    * @param self The in-memory struct    * @param key The key to search    * @return Whether the key exists in the map    * @return The value in map if it exists    */   function search{name}(Data memory self, {key_type} {key_storage_type} key)     internal     pure     returns (bool, {value_type} {value_storage_type})   {{     {value_type} {value_storage_type} defaultValue;     for (uint256 i = 0; i < {map_name}; i++) {{       {field_type} memory data = {val_name}[i];       if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{         return (true, data.value);       }}     }}     return (false, defaultValue);   }}    /**    * @dev Add key-value pair from a map    * @param self The in-memory struct    * @param key The key to add    * @param value The value to add    */   function add{name}(Data memory self, {key_type} {key_storage_type} key, {value_type} {value_storage_type} value)     internal     pure   {{     /**      * First search whether the key exists.      * If not, add to the array. Otherwise, replace the value.      * If a resize is needed, the array size will be doubled.      */     for (uint256 i = 0; i < {map_name}; i++) {{       {field_type} memory data = {val_name}[i];       if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{         {val_name}[i].value = value;         return;       }}     }}     if ({val_name}.length == 0) {{       {val_name} = new {field_type}[](10);     }}     if ({map_name} == {val_name}.length) {{       {field_type}[] memory tmp = new {field_type}[]({val_name}.length * 2);       for (uint256 i = 0; i < {map_name}; i++) {{         tmp[i] = {val_name}[i];       }}       {val_name} = tmp;     }}     {field_type} memory entry;     entry.key = key;     entry.value = value;     {val_name}[{map_name}++] = entry;   }}    /**    * @dev Delete key from a map    * @param self The in-memory struct    * @param key The key to delete    */   function rm{name}(Data memory self, {key_type} {key_storage_type} key) internal pure {{     /**      * First search whether the key exists.      * If not, do nothing.      * Otherwise, replace with last key-value pair in the array.      */     uint256 pos;     for (uint256 i = 0; i < {map_name}; i++) {{       {field_type} memory data = {val_name}[i];       if (keccak256(abi.encodePacked((key))) == keccak256(abi.encodePacked((data.key)))) {{         pos = i + 1;         break;       }}     }}     if (pos == 0) {{       return;     }}     pos -= 1;     {val_name}[pos] = {val_name}[--{map_name}];   }} //array helpers for {name}   /**    * @dev Add value to an array    * @param self The in-memory struct    * @param value The value to add    */   function add{name}(Data memory self, {field_type} {field_storage_type} value) internal pure {{     /**      * First resize the array. Then add the new element to the end.      */     {field_type}[] memory tmp = new {field_type}[]({val_name}.length + 1);     for (uint256 i = 0; i < {val_name}.length; i++) {{       tmp[i] = {val_name}[i];     }}     tmp[{val_name}.length] = value;     {val_name} = tmp;   }} library {delegate_lib_name} {{ {enum_definition} {struct_definition} {decoder_section} {encoder_section} {store_function} {map_helper} {array_helper} {utility_functions} }} //library {delegate_lib_name} library {delegate_lib_name} {{ {enum_definition} }} //library {delegate_lib_name}