sway/sway-lib-std/generate.sh
Daniel Frederico Lins Leite 6cc563d763
Some checks are pending
Codspeed Benchmarks / benchmarks (push) Waiting to run
CI / verifications-complete (push) Blocked by required conditions
CI / check-dependency-version-formats (push) Waiting to run
CI / check-forc-manifest-version (push) Waiting to run
CI / get-fuel-core-version (push) Waiting to run
CI / build-sway-lib-std (push) Waiting to run
CI / build-sway-examples (push) Waiting to run
CI / build-reference-examples (push) Waiting to run
CI / forc-fmt-check-sway-lib-std (push) Waiting to run
CI / forc-fmt-check-sway-examples (push) Waiting to run
CI / forc-fmt-check-panic (push) Waiting to run
CI / check-sdk-harness-test-suite-compatibility (push) Waiting to run
CI / build-mdbook (push) Waiting to run
CI / build-forc-doc-sway-lib-std (push) Waiting to run
CI / publish-sway-lib-std (push) Blocked by required conditions
CI / Build and upload forc binaries to release (push) Blocked by required conditions
CI / Build and test various forc tools (push) Blocked by required conditions
CI / cargo-unused-deps-check (push) Waiting to run
CI / notify-slack-on-failure (push) Blocked by required conditions
CI / pre-publish-check (push) Waiting to run
CI / publish (push) Blocked by required conditions
CI / build-forc-test-project (push) Waiting to run
CI / cargo-build-workspace (push) Waiting to run
CI / cargo-clippy (push) Waiting to run
CI / cargo-toml-fmt-check (push) Waiting to run
CI / cargo-fmt-check (push) Waiting to run
CI / cargo-run-e2e-test-release (push) Blocked by required conditions
CI / cargo-test-lib-std (push) Waiting to run
CI / forc-run-benchmarks (push) Waiting to run
CI / forc-unit-tests (push) Waiting to run
CI / forc-pkg-fuels-deps-check (push) Waiting to run
github pages / deploy (push) Waiting to run
Trivial fns allowing control if a type is trivially encoded/decoded (#7501)
## Description

Continuation of https://github.com/FuelLabs/sway/pull/7488.

This PR introduces the option for each type to control its own
`is_trivial`.

Primitive data types have direct implementation (only decoding bool is
false, as we need to guarantee its value is zero or one).

Structs, tuples, arrays etc... are trivial if their runtime
representation and "inner types" allow for trivial encoding or decoding.

Enums are more complicated as we need to control that the enum tag is
valid; they are not trivial.

String arrays are not trivially encoded/decoded for backwards
compatibility with "encoding v0" that needs padding in some cases.

Some tests are showing a small regression (6 gas), which comes from the
introduced "if" not being optimised away. I want to solve this in
another PR, where the "if" condition will come from a const, and IR
generation will guarantee that only one branch will ever be emitted.

## Snapshot "echo"

Small QOL of snapshot was introduced with the "echo" command. It just
prints the message directly, wrapping on 80 chars. The idea is to
explain what the snapshot is trying to test.

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [ ] If my change requires substantial documentation changes, I have
[requested support from the DevRel
team](https://github.com/FuelLabs/devrel-requests/issues/new/choose)
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [ ] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [ ] I have requested a review from the relevant team or maintainers.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Add per-type trivial encode/decode flags and use raw_ptr fast paths in
ABI (encode/decode) with supporting changes to codec, String/Vec, and
tests.
> 
> - **std/codec**:
> - Introduce `AbiEncode::is_encode_trivial` and
`AbiDecode::is_decode_trivial`; add helpers
`is_encode_trivial/is_decode_trivial`.
> - Switch `encode`/`abi_decode` to branch on triviality; add
`decode_from_raw_ptr` and raw-ptr-based `decode_*` helpers.
> - Make `BufferReader` parameter accessors return `raw_ptr`; minor
refactors to use raw ptr copies.
> - Implement triviality for primitives, arrays/tuples (conditional),
`str[strN]` non-trivial, enums non-trivial.
> - **std/string & std/vec**: implement trivial encode/decode markers
(non-trivial) and adapt codec impls.
> - **Tests/fixtures**:
> - Update snapshots (IR/ASM/bytecode/gas), JSON ABI offsets,
contract/predicate IDs, and logging expectations to match new encoding
paths.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
dddd944aba. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
2025-12-17 10:43:44 +11:00

265 lines
No EOL
9.5 KiB
Bash
Executable file

#! /bin/bash
# Needs to exist at least one line between them
remove_generated_code() {
START=`grep -n "BEGIN $1" ./src/$2`
START=${START%:*}
END=`grep -n "END $1" ./src/$2`
END=${END%:*}
sed -i "$((START+1)),$((END-1))d" ./src/$2
}
remove_generated_code "ARRAY_ENCODE" "codec.sw"
START=1
END=64
for ((i=END;i>=START;i--)); do
CODE="#[cfg(experimental_const_generics = false)]\nimpl<T> AbiEncode for [T; $i] where T: AbiEncode { fn is_encode_trivial() -> bool { is_encode_trivial::<T>() } fn abi_encode(self, buffer: Buffer) -> Buffer { let mut buffer = buffer; let mut i = 0; while i < $i { buffer = self[i].abi_encode(buffer); i += 1; }; buffer } }"
sed -i "s/\/\/ BEGIN ARRAY_ENCODE/\/\/ BEGIN ARRAY_ENCODE\n$CODE/g" ./src/codec.sw
done
remove_generated_code "ARRAY_DECODE" "codec.sw"
START=1
END=64
for ((i=END;i>=START;i--)); do
CODE="#[cfg(experimental_const_generics = false)]\nimpl<T> AbiDecode for [T; $i] where T: AbiDecode { fn is_decode_trivial() -> bool { is_decode_trivial::<T>() } fn abi_decode(ref mut buffer: BufferReader) -> [T; $i] { let first: T = buffer.decode::<T>(); let mut array = [first; $i]; let mut i = 1; while i < $i { array[i] = buffer.decode::<T>(); i += 1; }; array } }"
sed -i "s/\/\/ BEGIN ARRAY_DECODE/\/\/ BEGIN ARRAY_DECODE\n$CODE/g" ./src/codec.sw
done
remove_generated_code "STRARRAY_ENCODE" "codec.sw"
START=1
END=64
for ((i=END;i>=START;i--)); do
CODE="#[cfg(experimental_const_generics = false)]\nimpl AbiEncode for str[$i] { fn is_encode_trivial() -> bool { false } fn abi_encode(self, buffer: Buffer) -> Buffer { Buffer { buffer: __encode_buffer_append(buffer.buffer, self) } } }"
sed -i "s/\/\/ BEGIN STRARRAY_ENCODE/\/\/ BEGIN STRARRAY_ENCODE\n$CODE/g" ./src/codec.sw
done
remove_generated_code "STRARRAY_DECODE" "codec.sw"
START=1
END=64
for ((i=END;i>=START;i--)); do
CODE="#[cfg(experimental_const_generics = false)]\nimpl AbiDecode for str[$i] { fn is_decode_trivial() -> bool { false } fn abi_decode(ref mut buffer: BufferReader) -> str[$i] { let data = buffer.read_bytes($i); asm(s: data.ptr()) { s: str[$i] } } }"
sed -i "s/\/\/ BEGIN STRARRAY_DECODE/\/\/ BEGIN STRARRAY_DECODE\n$CODE/g" ./src/codec.sw
done
generate_tuple_encode() {
local CODE="impl<"
local elements=("$1")
for element in ${elements[@]}
do
CODE="$CODE $element,"
done
CODE="$CODE> AbiEncode for ("
for element in ${elements[@]}
do
CODE="$CODE $element,"
done
CODE="$CODE) where "
for element in ${elements[@]}
do
CODE="$CODE $element: AbiEncode, "
done
ISTRIVIAL=""
for element in ${elements[@]}
do
ISTRIVIAL="$ISTRIVIAL \&\& is_encode_trivial::<$element>()"
done
CODE="$CODE{ fn is_encode_trivial() -> bool { __runtime_mem_id::<Self>() == __encoding_mem_id::<Self>() $ISTRIVIAL } fn abi_encode(self, buffer: Buffer) -> Buffer { "
i=0
for element in ${elements[@]}
do
CODE="$CODE let buffer = self.$i.abi_encode(buffer);"
i=$((i+1))
done
CODE="$CODE buffer } }"
sed -i "s/\/\/ BEGIN TUPLES_ENCODE/\/\/ BEGIN TUPLES_ENCODE\n$CODE/g" ./src/codec.sw
}
remove_generated_code "TUPLES_ENCODE" "codec.sw"
generate_tuple_encode "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
generate_tuple_encode "A B C D E F G H I J K L M N O P Q R S T U V W X Y"
generate_tuple_encode "A B C D E F G H I J K L M N O P Q R S T U V W X"
generate_tuple_encode "A B C D E F G H I J K L M N O P Q R S T U V W"
generate_tuple_encode "A B C D E F G H I J K L M N O P Q R S T U V"
generate_tuple_encode "A B C D E F G H I J K L M N O P Q R S T U"
generate_tuple_encode "A B C D E F G H I J K L M N O P Q R S T"
generate_tuple_encode "A B C D E F G H I J K L M N O P Q R S"
generate_tuple_encode "A B C D E F G H I J K L M N O P Q R"
generate_tuple_encode "A B C D E F G H I J K L M N O P Q"
generate_tuple_encode "A B C D E F G H I J K L M N O P"
generate_tuple_encode "A B C D E F G H I J K L M N O"
generate_tuple_encode "A B C D E F G H I J K L M N"
generate_tuple_encode "A B C D E F G H I J K L M"
generate_tuple_encode "A B C D E F G H I J K L"
generate_tuple_encode "A B C D E F G H I J K"
generate_tuple_encode "A B C D E F G H I J"
generate_tuple_encode "A B C D E F G H I"
generate_tuple_encode "A B C D E F G H"
generate_tuple_encode "A B C D E F G"
generate_tuple_encode "A B C D E F"
generate_tuple_encode "A B C D E"
generate_tuple_encode "A B C D"
generate_tuple_encode "A B C"
generate_tuple_encode "A B"
generate_tuple_encode "A"
generate_tuple_decode() {
local CODE="impl<"
local elements=("$1")
for element in ${elements[@]}
do
CODE="$CODE $element,"
done
CODE="$CODE> AbiDecode for ("
for element in ${elements[@]}
do
CODE="$CODE $element,"
done
CODE="$CODE) where "
for element in ${elements[@]}
do
CODE="$CODE $element: AbiDecode, "
done
ISTRIVIAL=""
for element in ${elements[@]}
do
ISTRIVIAL="$ISTRIVIAL \&\& is_decode_trivial::<$element>()"
done
CODE="$CODE{ fn is_decode_trivial() -> bool { __runtime_mem_id::<Self>() == __encoding_mem_id::<Self>() $ISTRIVIAL } fn abi_decode(ref mut buffer: BufferReader) -> Self { ("
for element in ${elements[@]}
do
CODE="$CODE $element::abi_decode(buffer),"
done
CODE="$CODE) } }"
sed -i "s/\/\/ BEGIN TUPLES_DECODE/\/\/ BEGIN TUPLES_DECODE\n$CODE/g" ./src/codec.sw
}
remove_generated_code "TUPLES_DECODE" "codec.sw"
generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U V W X Y"
generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U V W X"
generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U V W"
generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U V"
generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U"
generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T"
generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S"
generate_tuple_decode "A B C D E F G H I J K L M N O P Q R"
generate_tuple_decode "A B C D E F G H I J K L M N O P Q"
generate_tuple_decode "A B C D E F G H I J K L M N O P"
generate_tuple_decode "A B C D E F G H I J K L M N O"
generate_tuple_decode "A B C D E F G H I J K L M N"
generate_tuple_decode "A B C D E F G H I J K L M"
generate_tuple_decode "A B C D E F G H I J K L"
generate_tuple_decode "A B C D E F G H I J K"
generate_tuple_decode "A B C D E F G H I J"
generate_tuple_decode "A B C D E F G H I"
generate_tuple_decode "A B C D E F G H"
generate_tuple_decode "A B C D E F G"
generate_tuple_decode "A B C D E F"
generate_tuple_decode "A B C D E"
generate_tuple_decode "A B C D"
generate_tuple_decode "A B C"
generate_tuple_decode "A B"
generate_tuple_decode "A"
generate_tuple_debug() {
local CODE="impl<"
local elements=("$1")
for element in ${elements[@]}
do
CODE="$CODE $element,"
done
CODE="$CODE> Debug for ("
for element in ${elements[@]}
do
CODE="$CODE $element,"
done
CODE="$CODE) where "
for element in ${elements[@]}
do
CODE="$CODE $element: Debug, "
done
CODE="$CODE{ fn fmt(self, ref mut f: Formatter) { let mut f = f.debug_tuple(\"\");"
i=0
for element in ${elements[@]}
do
CODE="$CODE let mut f = f.field(self.$i);"
i=$((i+1))
done
CODE="$CODE f.finish(); } }"
sed -i "s/\/\/ BEGIN TUPLES_DEBUG/\/\/ BEGIN TUPLES_DEBUG\n$CODE/g" ./src/debug.sw
}
remove_generated_code "TUPLES_DEBUG" "debug.sw"
generate_tuple_debug "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
generate_tuple_debug "A B C D E F G H I J K L M N O P Q R S T U V W X Y"
generate_tuple_debug "A B C D E F G H I J K L M N O P Q R S T U V W X"
generate_tuple_debug "A B C D E F G H I J K L M N O P Q R S T U V W"
generate_tuple_debug "A B C D E F G H I J K L M N O P Q R S T U V"
generate_tuple_debug "A B C D E F G H I J K L M N O P Q R S T U"
generate_tuple_debug "A B C D E F G H I J K L M N O P Q R S T"
generate_tuple_debug "A B C D E F G H I J K L M N O P Q R S"
generate_tuple_debug "A B C D E F G H I J K L M N O P Q R"
generate_tuple_debug "A B C D E F G H I J K L M N O P Q"
generate_tuple_debug "A B C D E F G H I J K L M N O P"
generate_tuple_debug "A B C D E F G H I J K L M N O"
generate_tuple_debug "A B C D E F G H I J K L M N"
generate_tuple_debug "A B C D E F G H I J K L M"
generate_tuple_debug "A B C D E F G H I J K L"
generate_tuple_debug "A B C D E F G H I J K"
generate_tuple_debug "A B C D E F G H I J"
generate_tuple_debug "A B C D E F G H I"
generate_tuple_debug "A B C D E F G H"
generate_tuple_debug "A B C D E F G"
generate_tuple_debug "A B C D E F"
generate_tuple_debug "A B C D E"
generate_tuple_debug "A B C D"
generate_tuple_debug "A B C"
generate_tuple_debug "A B"
generate_tuple_debug "A"
remove_generated_code "STRARRAY_DEBUG" "debug.sw"
START=1
END=64
for ((i=END;i>=START;i--)); do
CODE="#[cfg(experimental_const_generics = false)]\nimpl Debug for str[$i] { fn fmt(self, ref mut f: Formatter) { use ::str::*; from_str_array(self).fmt(f); } }"
sed -i "s/\/\/ BEGIN STRARRAY_DEBUG/\/\/ BEGIN STRARRAY_DEBUG\n$CODE/g" ./src/debug.sw
done
remove_generated_code "ARRAY_DEBUG" "debug.sw"
START=1
END=64
for ((i=END;i>=START;i--)); do
CODE="#[cfg(experimental_const_generics = false)]\nimpl<T> Debug for [T; $i] where T: Debug { fn fmt(self, ref mut f: Formatter) { let mut f = f.debug_list(); let mut i = 0; while i < $i { f = f.entry(self[i]); i += 1; }; f.finish(); } }"
sed -i "s/\/\/ BEGIN ARRAY_DEBUG/\/\/ BEGIN ARRAY_DEBUG\n$CODE/g" ./src/debug.sw
done
cargo r -p forc-fmt --release -- -p .