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

absl::Status in Rust

NOTE: The APIs here have planned future backwards-incompatible changes, and you may see LSCs as we migrate to the end state API.

In Google C++, the standard types for communicating an error are absl::Status and absl::StatusOr<T>. These have support in Rust when they are directly passed by value, or returned by value, and are mapped to a Rust Result. For example:

absl::Status Foo();

This becomes:

#![allow(unused)]
fn main() {
pub fn Foo() -> Result<(), StatusError> {...}
}

(Specifically, it will return Status, which is an alias for Result<(), StatusError>.)

Calling C++ APIs using Status

C++ functions returning Status/StatusOr can be defined as normal:

// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef THIRD_PARTY_CRUBIT_EXAMPLES_TYPES_ABSL_STATUS_CPP_API_H_
#define THIRD_PARTY_CRUBIT_EXAMPLES_TYPES_ABSL_STATUS_CPP_API_H_

#include "absl/status/status.h"
#include "absl/status/statusor.h"

absl::Status ReturnsStatus(bool ok);

absl::StatusOr<int> ReturnsStatusOrInt(bool ok);

#endif  // THIRD_PARTY_CRUBIT_EXAMPLES_TYPES_ABSL_STATUS_CPP_API_H_

…and will return a Result:

// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

use googletest::prelude::*;

#[gtest]
fn test_returns_status() {
    let status = cpp_api::ReturnsStatus(true);
    expect_true!(status.is_ok());
}

#[gtest]
fn test_returns_status_or_int() {
    let status_or_int = cpp_api::ReturnsStatusOrInt(true);
    expect_eq!(status_or_int, Ok(42));
}

Calling Rust APIs using Status

Unlike when calling C++ APIs, currently you cannot directly call a Rust API returning a Status or StatusOr. Instead, it must use a workaround type, StatusWrapper. This is tracked by b/441266536.

// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

/// This function is only callable from Rust (for now).
pub fn returns_status(ok: bool) -> status::Status {
    if ok {
        status::OkStatus()
    } else {
        Err(status::internal("Something went wrong, oh no!"))
    }
}

/// This function is callable from C++.
#[allow(non_snake_case)]
pub fn ReturnsStatus(ok: bool) -> status_wrapper::StatusWrapper {
    returns_status(ok).into()
}

The StatusWrapper type automatically becomes an absl::Status in C++:

// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "examples/types/absl_status/rust_api.h"

namespace {

TEST(UserOfRustApiTest, ReturnsStatus) {
  // Cannot call returns_status() directly for now,
  // and need to call .status() on a `StatusWrapper` return
  // value instead.
  EXPECT_OK(rust_api::ReturnsStatus(true).status());
}

}  // namespace

Future Evolution

We expect to stop using Result, and instead use the plain actual bindings for absl::Status itself, using the Try trait to enable conversion into Result and error handling via ?.

This would allow Status to be used not only as function parameter and return values, but also in struct fields, arrays, or behind pointers and references.

However, this is blocked on stabilization of the Try trait.