Rix is the official package layer for Vix.cpp Browse packages
Skip to content

Format ​

This page explains the formatting helpers provided by rix/debug.

The examples use the public Rix facade:

cpp
#include <rix.hpp>

and access formatting through:

cpp
rix.debug.format

Formatting is useful when you want to build a string with placeholders before printing it, storing it, returning it, or passing it to another API.

For production application logs, prefer the Vix logging system.

Basic example ​

Create a file:

bash
mkdir -p ~/rix-debug-format
cd ~/rix-debug-format
touch format.cpp

Add:

cpp
#include <rix.hpp>

#include <string>

int main()
{
  const std::string one =
      rix.debug.format("Hello, {}", "Ada");

  const std::string two =
      rix.debug.format(
          "{0} builds on {1}",
          "Rix",
          "Vix.cpp");

  const std::string three =
      rix.debug.format(
          "{{ package }} = {}",
          "rix/debug");

  rix.debug.print(one);
  rix.debug.print(two);
  rix.debug.print(three);

  return 0;
}

Run it:

bash
vix run format.cpp

If Rix is not available yet for single-file usage:

bash
vix install -g rix/rix
vix run format.cpp

Expected output ​

The output should look like this:

txt
Hello, Ada
Rix builds on Vix.cpp
{ package } = rix/debug

rix.debug.format ​

Use:

cpp
rix.debug.format(...)

to create a formatted string.

Example:

cpp
const auto message =
    rix.debug.format("Package: {}", "rix/debug");

rix.debug.print(message);

Output:

txt
Package: rix/debug

format returns a std::string.

It does not print by itself.

Automatic placeholders ​

Use {} to insert arguments in order:

cpp
const auto message =
    rix.debug.format("{} uses {}", "Rix", "C++");

Output:

txt
Rix uses C++

Each {} consumes the next argument.

Example:

cpp
const auto message =
    rix.debug.format(
        "name: {}, language: {}, rows: {}",
        "Ada",
        "C++",
        3);

Output:

txt
name: Ada, language: C++, rows: 3

Explicit placeholders ​

Use {0}, {1}, and other numeric indexes when the position should be explicit:

cpp
const auto message =
    rix.debug.format("{0} + {0} = {1}", "C++", "Vix.cpp");

Output:

txt
C++ + C++ = Vix.cpp

Explicit indexes are useful when the same value appears more than once.

Do not mix placeholder styles ​

Do not mix automatic placeholders and explicit placeholders in the same format string.

Wrong:

cpp
rix.debug.format("{} {0}", "Rix");

Use automatic placeholders:

cpp
rix.debug.format("{} {}", "Rix", "Debug");

or explicit placeholders:

cpp
rix.debug.format("{0} {1}", "Rix", "Debug");

Escaped braces ​

Use double opening braces and double closing braces when you need literal braces:

cpp
const auto message =
    rix.debug.format("{{ package }} = {}", "rix/debug");

Output:

txt
{ package } = rix/debug

This is useful when printing template-like text, configuration blocks, or examples.

Unsupported format specifiers ​

rix.debug.format intentionally keeps formatting small.

It does not support format specifiers such as:

txt
{:>10}
{:.2f}
{:04d}

Wrong:

cpp
rix.debug.format("{:.2f}", 3.14159);

Use simple placeholders:

cpp
rix.debug.format("value: {}", 3.14159);

For advanced formatting, use another formatting library or normal C++ formatting tools where appropriate.

Format different value types ​

rix.debug.format uses the Rix rendering pipeline.

You can format strings, numbers, booleans, and other supported printable values.

cpp
const auto message =
    rix.debug.format(
        "name: {}, rows: {}, ready: {}",
        "Ada",
        3,
        true);

rix.debug.print(message);

Output shape:

txt
name: Ada, rows: 3, ready: true

Append formatted output ​

Use:

cpp
rix.debug.format.append(...)

to append formatted text to an existing string.

Example:

cpp
std::string out = "Rix: ";

rix.debug.format.append(
    out,
    "{}",
    "debug");

rix.debug.print(out);

Output:

txt
Rix: debug

Append is useful when you are building a longer string in steps.

Replace a string with formatted output ​

Use:

cpp
rix.debug.format.to(...)

to replace an existing string with formatted output.

Example:

cpp
std::string out = "old value";

rix.debug.format.to(
    out,
    "Package: {}",
    "rix/debug");

rix.debug.print(out);

Output:

txt
Package: rix/debug

The previous content of out is cleared.

format vs print ​

Use format when you need a string:

cpp
const auto message =
    rix.debug.format("rows: {}", 3);

rix.debug.print(message);

Use print when you only want to write values immediately:

cpp
rix.debug.print("rows:", 3);

print separates values with spaces.

format replaces placeholders and returns a string.

format vs sprint ​

Use format when you want placeholder-based formatting:

cpp
const auto message =
    rix.debug.format("Package: {}", "rix/debug");

Use sprint when you want the same rendering style as print, but returned as a string:

cpp
const auto line =
    rix.debug.sprint("Package:", "rix/debug");

Both return std::string.

The difference is the style:

txt
format -> placeholder replacement
sprint -> print-style value joining

Complete append example ​

cpp
#include <rix.hpp>

#include <string>

int main()
{
  std::string output;

  rix.debug.format.append(
      output,
      "package: {}\n",
      "rix/debug");

  rix.debug.format.append(
      output,
      "status: {}\n",
      "ready");

  rix.debug.format.append(
      output,
      "rows: {}\n",
      3);

  rix.debug.print(output);

  return 0;
}

Run:

bash
vix run format.cpp

Expected output:

txt
package: rix/debug
status: ready
rows: 3

Complete replace example ​

cpp
#include <rix.hpp>

#include <string>

int main()
{
  std::string message;

  rix.debug.format.to(
      message,
      "Hello, {}",
      "Rix");

  rix.debug.print(message);

  rix.debug.format.to(
      message,
      "Package: {}",
      "rix/debug");

  rix.debug.print(message);

  return 0;
}

Run:

bash
vix run format.cpp

Expected output:

txt
Hello, Rix
Package: rix/debug

Formatting errors ​

Invalid format strings can throw rixlib::format_error.

Examples of invalid usage:

cpp
rix.debug.format("{", "Rix");
rix.debug.format("}", "Rix");
rix.debug.format("{2}", "Rix");
rix.debug.format("{} {0}", "Rix");
rix.debug.format("{:.2f}", 3.14);

For examples and small tools, keep format strings simple.

For user-provided format strings, handle errors explicitly.

Example:

cpp
try
{
  const auto message =
      rix.debug.format("{} {}", "Rix", "Debug");

  rix.debug.print(message);
}
catch (const rixlib::format_error &error)
{
  rix.debug.eprint("format error:", error.what());
  return 1;
}

Format CSV output messages ​

Formatting is useful when reporting CSV results:

cpp
#include <rix.hpp>

int main()
{
  const auto table = rix.csv.parse(
      "name,language\n"
      "Ada,C++\n"
      "Gaspard,Vix\n");

  const auto message =
      rix.debug.format("loaded {} rows", table.size());

  rix.debug.print(message);

  return 0;
}

Format Auth errors ​

Formatting can help create readable Auth diagnostics:

cpp
#include <rix.hpp>

int main()
{
  auto auth = rix.auth.memory();

  auto login = auth.login({
      "ada@example.com",
      "wrong-password"});

  if (login.failed())
  {
    const auto &error = login.error();

    const auto message =
        rix.debug.format(
            "auth error: {}: {}",
            rix.auth.error.to_string(error),
            error.message());

    rix.debug.eprint(message);
    return 1;
  }

  return 0;
}

Do not format or print authentication secrets in production.

Avoid printing:

txt
plain-text passwords
password hashes
session ids
raw token values

Format PDF messages ​

Formatting is useful when reporting generated files:

cpp
#include <rix.hpp>

int main()
{
  auto saved = rix.pdf.make_text(
      "hello.pdf",
      "Hello from rix.pdf",
      "Rix PDF");

  if (saved.failed())
  {
    const auto message =
        rix.debug.format(
            "pdf error: {}: {}",
            rix.pdf.error.to_string(saved.error()),
            saved.error().message());

    rix.debug.eprint(message);
    return 1;
  }

  rix.debug.print(
      rix.debug.format("created: {}", "hello.pdf"));

  return 0;
}

Use in a Vix project ​

Create a Vix application:

bash
vix new debug-format --app
cd debug-format

Add Rix:

bash
vix add rix/rix
vix install

In vix.app, make sure Rix is listed under deps:

txt
deps = [
  "rix/rix",
]

A small vix.app can look like this:

txt
name = "debug-format"
type = "executable"
standard = "c++20"
output_dir = "bin"

sources = [
  "src/main.cpp",
]

include_dirs = [
  "include",
  "src",
]

deps = [
  "rix/rix",
]

packages = [
  "vix",
]

links = [
  "vix::vix",
]

Then use formatting in src/main.cpp:

cpp
#include <rix.hpp>

int main()
{
  const auto message =
      rix.debug.format("Package: {}", "rix/debug");

  rix.debug.print(message);

  return 0;
}

Build and run:

bash
vix build
vix run

Single-file usage ​

For small scripts, examples, and experiments:

bash
vix run format.cpp

If Rix is installed globally for single-file usage:

bash
vix install -g rix/rix
vix run format.cpp

For project usage, prefer:

bash
vix add rix/rix
vix install

and keep the dependency in vix.app:

txt
deps = [
  "rix/rix",
]

Use only Debug with the facade ​

If you want the rix.* facade style but only want Debug mounted, define the feature macro before including rix.hpp:

cpp
#define RIX_ENABLE_DEBUG
#include <rix.hpp>

int main()
{
  const auto message =
      rix.debug.format("Hello, {}", "Rix");

  rix.debug.print(message);

  return 0;
}

When at least one RIX_ENABLE_* macro is defined, only selected modules are mounted.

Use the independent package ​

For independent usage, install:

bash
vix add rix/debug
vix install

In vix.app:

txt
deps = [
  "rix/debug",
]

Then include the independent package header:

cpp
#include <rix/debug.hpp>

Use this style when a project only needs Debug and does not need the full unified Rix facade.

For most application documentation, prefer:

cpp
#include <rix.hpp>

Logging note ​

rix.debug.format creates strings.

It is useful for examples and local diagnostics.

For real application logs, prefer the Vix logging system.

Use this rule:

txt
rix.debug -> examples, local diagnostics, quick tools
Vix logging -> production logs, service logs, request logs

Common mistakes ​

Expecting print to replace placeholders ​

Wrong:

cpp
rix.debug.print("Package: {}", "rix/debug");

Use format:

cpp
rix.debug.print(
    rix.debug.format("Package: {}", "rix/debug"));

Mixing automatic and explicit placeholders ​

Wrong:

cpp
rix.debug.format("{} {0}", "Rix");

Use one style:

cpp
rix.debug.format("{} {}", "Rix", "Debug");

or:

cpp
rix.debug.format("{0} {1}", "Rix", "Debug");

Using unsupported format specifiers ​

Wrong:

cpp
rix.debug.format("{:.2f}", 3.14159);

Use simple placeholders:

cpp
rix.debug.format("value: {}", 3.14159);

Forgetting escaped braces ​

Wrong:

cpp
rix.debug.format("{ package } = {}", "rix/debug");

Use:

cpp
rix.debug.format("{{ package }} = {}", "rix/debug");

Formatting secrets ​

Do not format or print:

txt
plain-text passwords
password hashes
session ids
raw token values

This matters especially with rix/auth.

Forgetting deps ​

For a Vix project, do not put Rix packages in packages.

Use:

txt
deps = [
  "rix/rix",
]

packages is for CMake package discovery.

deps is for Vix Registry packages.

What you should remember ​

Format a string:

cpp
auto message = rix.debug.format("Hello, {}", "Rix");

Use automatic placeholders:

cpp
rix.debug.format("{} uses {}", "Rix", "C++");

Use explicit placeholders:

cpp
rix.debug.format("{0} + {0} = {1}", "C++", "Vix.cpp");

Escape braces:

cpp
rix.debug.format("{{ package }} = {}", "rix/debug");

Append:

cpp
rix.debug.format.append(out, "{}", "debug");

Replace:

cpp
rix.debug.format.to(out, "Package: {}", "rix/debug");

Use simple placeholders only.

For a Vix project, install Rix:

bash
vix add rix/rix
vix install

and use:

txt
deps = [
  "rix/rix",
]

Next step ​

Learn inspection.

Next: Inspect

Released under the MIT License.