Add `byteLengthWithFallback` to ShortStrings (#4089)

Co-authored-by: Francisco <fg@frang.io>
pull/4091/head
Hadrien Croubois 2 years ago committed by GitHub
parent 7f028d6959
commit de520fe25a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      contracts/utils/ShortStrings.sol
  2. 5
      test/utils/ShortStrings.test.js

@ -54,7 +54,7 @@ library ShortStrings {
* @dev Decode a `ShortString` back to a "normal" string. * @dev Decode a `ShortString` back to a "normal" string.
*/ */
function toString(ShortString sstr) internal pure returns (string memory) { 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. // using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32); string memory str = new string(32);
/// @solidity memory-safe-assembly /// @solidity memory-safe-assembly
@ -68,7 +68,7 @@ library ShortStrings {
/** /**
* @dev Return the length of a `ShortString`. * @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; uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) { if (result > 31) {
revert InvalidShortString(); revert InvalidShortString();
@ -98,4 +98,18 @@ library ShortStrings {
return store; 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;
}
}
} }

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

Loading…
Cancel
Save