Parcourir la source

Add `byteLengthWithFallback` to ShortStrings (#4089)

Co-authored-by: Francisco <fg@frang.io>
Hadrien Croubois il y a 2 ans
Parent
commit
de520fe25a
2 fichiers modifiés avec 20 ajouts et 3 suppressions
  1. 16 2
      contracts/utils/ShortStrings.sol
  2. 4 1
      test/utils/ShortStrings.test.js

+ 16 - 2
contracts/utils/ShortStrings.sol

@@ -54,7 +54,7 @@ library ShortStrings {
      * @dev Decode a `ShortString` back to a "normal" string.
      */
     function toString(ShortString sstr) internal pure returns (string memory) {
-        uint256 len = length(sstr);
+        uint256 len = byteLength(sstr);
         // using `new string(len)` would work locally but is not memory safe.
         string memory str = new string(32);
         /// @solidity memory-safe-assembly
@@ -68,7 +68,7 @@ library ShortStrings {
     /**
      * @dev Return the length of a `ShortString`.
      */
-    function length(ShortString sstr) internal pure returns (uint256) {
+    function byteLength(ShortString sstr) internal pure returns (uint256) {
         uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
         if (result > 31) {
             revert InvalidShortString();
@@ -98,4 +98,18 @@ library ShortStrings {
             return store;
         }
     }
+
+    /**
+     * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
+     *
+     * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
+     * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
+     */
+    function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
+        if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
+            return byteLength(value);
+        } else {
+            return bytes(store).length;
+        }
+    }
 }

+ 4 - 1
test/utils/ShortStrings.test.js

@@ -23,7 +23,7 @@ contract('ShortStrings', function () {
           const encoded = await this.mock.$toShortString(str);
           expect(decode(encoded)).to.be.equal(str);
 
-          const length = await this.mock.$length(encoded);
+          const length = await this.mock.$byteLength(encoded);
           expect(length.toNumber()).to.be.equal(str.length);
 
           const decoded = await this.mock.$toString(encoded);
@@ -44,6 +44,9 @@ contract('ShortStrings', function () {
           await expectRevertCustomError(promise, 'InvalidShortString()');
         }
 
+        const length = await this.mock.$byteLengthWithFallback(ret0, 0);
+        expect(length.toNumber()).to.be.equal(str.length);
+
         const recovered = await this.mock.$toStringWithFallback(ret0, 0);
         expect(recovered).to.be.equal(str);
       });