ShortStrings.sol 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.8;
  3. import "./StorageSlot.sol";
  4. type ShortString is bytes32;
  5. /**
  6. * @dev This library provides functions to convert short memory strings
  7. * into a `ShortString` type that can be used as an immutable variable.
  8. * Strings of arbitrary length can be optimized if they are short enough by
  9. * the addition of a storage variable used as fallback.
  10. *
  11. * Usage example:
  12. *
  13. * ```solidity
  14. * contract Named {
  15. * using ShortStrings for *;
  16. *
  17. * ShortString private immutable _name;
  18. * string private _nameFallback;
  19. *
  20. * constructor(string memory contractName) {
  21. * _name = contractName.toShortStringWithFallback(_nameFallback);
  22. * }
  23. *
  24. * function name() external view returns (string memory) {
  25. * return _name.toStringWithFallback(_nameFallback);
  26. * }
  27. * }
  28. * ```
  29. */
  30. library ShortStrings {
  31. error StringTooLong(string str);
  32. /**
  33. * @dev Encode a string of at most 31 chars into a `ShortString`.
  34. *
  35. * This will trigger a `StringTooLong` error is the input string is too long.
  36. */
  37. function toShortString(string memory str) internal pure returns (ShortString) {
  38. bytes memory bstr = bytes(str);
  39. if (bstr.length > 31) {
  40. revert StringTooLong(str);
  41. }
  42. return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
  43. }
  44. /**
  45. * @dev Decode a `ShortString` back to a "normal" string.
  46. */
  47. function toString(ShortString sstr) internal pure returns (string memory) {
  48. uint256 len = length(sstr);
  49. // using `new string(len)` would work locally but is not memory safe.
  50. string memory str = new string(32);
  51. /// @solidity memory-safe-assembly
  52. assembly {
  53. mstore(str, len)
  54. mstore(add(str, 0x20), sstr)
  55. }
  56. return str;
  57. }
  58. /**
  59. * @dev Return the length of a `ShortString`.
  60. */
  61. function length(ShortString sstr) internal pure returns (uint256) {
  62. return uint256(ShortString.unwrap(sstr)) & 0xFF;
  63. }
  64. /**
  65. * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
  66. */
  67. function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
  68. if (bytes(value).length < 32) {
  69. return toShortString(value);
  70. } else {
  71. StorageSlot.getStringSlot(store).value = value;
  72. return ShortString.wrap(0);
  73. }
  74. }
  75. /**
  76. * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
  77. */
  78. function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
  79. if (length(value) > 0) {
  80. return toString(value);
  81. } else {
  82. return store;
  83. }
  84. }
  85. }