Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

TVF

Tag Value Field is the internal message interface used by ProSA.

It’s not a full-fledged format but a Rust trait that defines what a message format should support.

Currently, only the SimpleStringTvf implementation exists. However, in the future, others could implement the TVF trait, such as ProtoBuf, and more.

Usage

In ProSA, Tvf is used as a generic message type that can support various serialization strategies. The trait allows you to:

  • Add fields using put_* methods
  • Retrieve fields using get_* methods
  • Access information from the container

Most of the time, when using a component that use TVF, you’ll see a generic declaration like:

struct StructObject<M>
where
    M: 'static
        + std::marker::Send
        + std::marker::Sync
        + std::marker::Sized
        + std::clone::Clone
        + std::fmt::Debug
        + prosa_utils::msg::tvf::Tvf
        + std::default::Default,
{
    fn create_tvf() -> M {
        let buffer = M::default();
        buffer.put_string(1, "value");
        println!("TVF contains: {buffer:?}");
        buffer
    }
}

To create a TVF, the Default trait must be implemented.

Good to have are Clone and Debug for your TVF. When TVFs are used for messaging, Send and Sync are essential to safely move them across threads.

Constructing TVF Messages with the tvf! Macro

Instead of manually calling put_* methods one by one, you can use the tvf! procedural macro to construct TVF messages with a concise syntax.

Basic usage (map)

Create a TVF with key-value pairs using =>:

use prosa_macros::tvf;
use prosa_utils::msg::simple_string_tvf::SimpleStringTvf;

let message = tvf!(SimpleStringTvf {
    1 => "hello",
    2 => 42,
    3 => 3.14,
});

Integer values are inferred as signed (i64) by default. Use type suffixes or as casts to specify other types:

let message = tvf!(SimpleStringTvf {
    1 => 2,              // signed (i64)
    2 => 4usize,         // also signed
    3 => 1 as Unsigned,  // unsigned (u64)
    4 => 2.5 as Float,   // float (f64)
});

Type annotations

Use as Type to explicitly set the field type:

AnnotationRust typeExample
as Unsignedu641 as Unsigned
as Signedi64-5 as Signed
as Floatf643.14 as Float
as Byteu822 as Byte
as BytesBytes0x01020304 as Bytes
as DateNaiveDate"1995-01-10" as Date
as DateTimeNaiveDateTime"2023-06-05 15:02:00.000" as DateTime

Lists

Use [ ] to create sequential fields indexed starting from 1:

let list = tvf!(SimpleStringTvf [
    "first element",   // index 1
    "second element",  // index 2
    42,                // index 3
]);

Nested buffers

Nest TVF structures inside other TVF messages:

let message = tvf!(SimpleStringTvf {
    1 => 2,
    5 => [
        1 as Unsigned,
        2 as Float,
        3,
        "four",
        5 as Byte,
        {
            1 => "nested object",
            2 => 0x00010203 as Bytes,
        }
    ],
    6 => "1995-01-10" as Date,
    200 => "2023-06-05 15:02:00.000" as DateTime,
});

Lists can contain nested maps ({ }), and maps can contain nested lists ([ ]), allowing arbitrary depth.

Implement your own TVF

If you have your own internal format, you can implement the TVF trait on your own and expose your TVF struct:

impl Tvf for MyOwnTvf {
    // All trait method must be implement here
}

Make sure to also implement:

  • Default: to create an empty or initial TVF
  • Send/Sync: to safely transfer across threads
  • Clone: if duplication of buffers is needed
  • Debug: To enable easy debugging and inspection

Declare your custom TVF

When you implement your own TVF, you need to expose it in your Cargo.toml metadata as discussed in the previous chapter.

To do this, add the following to your Cargo.toml file:

[package.metadata.prosa]
tvf = ["tvf::MyOwnTvf"]

Be sure to specify the entire path of your implementation, tvf::MyOwnTvf, in this case, if you place it in src/tvf.rs.

Handling sensitive data

At Worldline, since we process payments, messages may contain sensitive data. This data must not be printed or extracted from the application to ensure security.

To address this, ProSA provides the TvfFilter trait, which allows filtering and masking sensitive fields.

Depending on your message, sensitive field may vary. Since TvfFilter is a trait, you can implement your own filter tailored to your message format.