Convert str -> str[64] with padding

I’m working on a Sway smart contract and need to convert a str of variable length into a str[64]. If the string is shorter than 64 characters, I want to pad it with zeroes ("0") or spaces until it reaches exactly 64 characters. However, I’m not sure how to do this in Sway since string manipulation is limited.

Hi :wave:
Not sure what way you want this padded, but maybe you are looking for something like the below. The function string_to_bytes_padded() maintains the original string content and pads the remaining space with ASCII ‘0’ characters (hex 0x30). Returns None if the input string is longer than 64 characters, otherwise it returns the padded string as an Option<String>.

.sw

library;

use std::{
    bytes::Bytes,
    string::String,
};



pub fn string_to_bytes_padded(input_string: String) -> Option<String> {

    let input_capacity = input_string.capacity();
    // Check if the input string is already greater than 64 chars.
    if input_capacity > 64 {
        return None;
    }
    let mut padded_bytes = Bytes::new();
    // Copy the input bytes
    let input_slice = asm(ptr: (input_string.ptr(), input_string.capacity())) {
        ptr: raw_slice
    };
    let input_bytes = Bytes::from(input_slice);
    // copy data and padd if necessary
    let mut i = 0;
    while i < input_capacity {
        padded_bytes.push(input_bytes.get(i).unwrap());
        i += 1;
    }
    // Pad with zeros up to 64 bytes
    while i < 64 {
        padded_bytes.push(0x30);
        i += 1;
    }
    Some(String::from_ascii(padded_bytes))
}


// forc test test_basic_conversion --logs
#[test()]
fn test_basic_conversion() {


    let mut some_string = String::from_ascii_str("AB");
    // log(some_string.capacity());
    let result_string = string_to_bytes_padded(some_string).unwrap();

    assert(result_string.capacity() == 64); // check result string is 64 chars

    let result_slice = asm(ptr: (result_string.ptr(), result_string.capacity())) {
        ptr: raw_slice
    };
    let result_bytes = Bytes::from(result_slice);

    // check start is 'AB'
    assert(result_bytes.get(0).unwrap() == 0x41);
    assert(result_bytes.get(1).unwrap() == 0x42);
    // Check that the middle is '0'
    let mut k = 2;
    while k < 64 {
        assert(result_bytes.get(k).unwrap() == 0x30);
        k += 1;
    }
}

// forc test test_max_capacity --logs
#[test()]
fn test_max_capacity() {

    let mut some_string = String::from_ascii_str("A00000000000000000000000000000000000000000000000000000000000000B");
    // log(some_string.capacity());
    let result_string = string_to_bytes_padded(some_string).unwrap();

    assert(result_string.capacity() == 64); // check result string is 64 chars

    let result_slice = asm(ptr: (result_string.ptr(), result_string.capacity())) {
        ptr: raw_slice
    };
    let result_bytes = Bytes::from(result_slice);

    assert(result_bytes.get(0).unwrap() == 0x41); // check start is 'A'
    // Check that the middle is '0'
    let mut k = 1;
    while k < 63 {
        assert(result_bytes.get(k).unwrap() == 0x30);
        k += 1;
    }
    assert(result_bytes.get(63).unwrap() == 0x42); // check end is 'B'
}

// forc test test_over_capacity --logs
#[test()]
fn test_over_capacity() {

    let mut some_string = String::from_ascii_str("A00000000000000000000000000000000000000000000000000000000000000BC");
    let result_string = string_to_bytes_padded(some_string);
    assert(result_string == None); // check None is returned if called with > 64 chars.
}

fuel-toolchain.toml

[toolchain]
channel = "testnet-2024-09-06"

[components]
forc = "0.63.5"
fuel-core = "0.35.0"

test with:

$ forc test

     Running 3 tests, filtered 0 tests
      test test_basic_conversion ... ok (15.236754ms, 16721 gas)
      test test_max_capacity ... ok (21.170787ms, 23418 gas)
      test test_over_capacity ... ok (741.145µs, 413 gas)

Great ! Thanks a lot. And can later String be converted to StorageString ? As I cam across such problem because i cant store not fixed size data in storage, so storing String will also be problem

I assume so, i dont know what your contract logic is but you should be able to store your padded strings with something like:

storage.storage_string.write_slice(padded_string);

snippet from the link below

use std::storage::storage_string::*;

storage {
    storage_string: StorageString = StorageString {},
}

...
    #[storage(write)]
    fn store_string() {
        // ANCHOR: string_storage_write
        let my_string = String::from_ascii_str("Fuel is blazingly fast");
        storage.storage_string.write_slice(my_string);
        // ANCHOR_END: string_storage_write
    }

check out:

In my contract in storage I have map from uint to struct and that struct has properties of type StorageString. I tried to use write_slice but got error No method named "write_slice" found for type "StorageString"

can you post a section of you Contract code, and the fuel toolchain version you are using?

                dstAddress: StorageString,
                dstChain: StorageString,
                dstAsset: StorageString,
                srcAsset: StorageString,
                sender: Address,
                srcReceiver: Address,
                hashlock: b256,
                timelock: u64,
                amount: u64,
                secret: u256,
                assetId: AssetId,
                redeemed: bool,
                refunded: bool
}

storage {
    contracts: StorageMap<u256, HTLC> = StorageMap::<u256, HTLC> {},} ```   and here is complete data of versions ```Installed toolchains
--------------------
latest-x86_64-unknown-linux-gnu (default)

active toolchain
----------------
latest-x86_64-unknown-linux-gnu (default)
  forc : 0.64.0
    - forc-client
      - forc-deploy : 0.64.0
      - forc-run : 0.64.0
    - forc-crypto : 0.64.0
    - forc-debug : 0.64.0
    - forc-doc : 0.64.0
    - forc-fmt : 0.64.0
    - forc-lsp : 0.64.0
    - forc-tx : 0.64.0
    - forc-wallet : 0.9.1
  fuel-core : 0.36.0
  fuel-core-keygen : 0.36.0

fuels versions
--------------
forc : 0.66
forc-wallet : 0.66.5```

or even in struct can be stored not StorageString but str[64]. I suppose getting str[ ] from String should be much more easy