mirror of
https://github.com/FuelLabs/sway.git
synced 2025-12-23 10:11:56 +00:00
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
## 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 -->
265 lines
No EOL
9.5 KiB
Bash
Executable file
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 . |