Rust: pbjson crate에서 “redundant reference” 경고

로컬에서 lint 검사 까지 마치고 서버로 push 했는데, 로컬에서 보이지 않았던 "redundant referece" 경고가 뜨면서 clippy를 수행하는 Rust용 CI가 실패 했다. 현재 프로젝트에서 Rust용 CI는 경고만 떠도 실패로 간주하는 -D warnings 파라미터를 설정하고 있는데 이것 때문에 CI 전체가 실패하는 문제가 생겼다.

로컬과의 차이점을 살펴 보니, local에서는 Cargo 1.94.1 버전을 사용하는데 반해, CI 서버에는 stable latest를 사용하도록 설정해 두어서 2026년 7월 현재 가장 최신 안정버전인 1.97.1을 사용하고 있었다.

이 버전에는 useless_borrow_in_formatting이라는 새로운 lint 항목이 추가 되었는데, 이것은 이미 reference인 변수에 중복해서 borrowing을 시도하는 경우 경고를 띄우는 검사항목이다.

문제가 발생하는 코드는 proto 파일로 부터 자동으로 serde Serialize / Deserialize 항목을 생성해 주는 pbjson이 만든 것으로, clippy는 원래 다른 모듈에 의해 생성되는 코드는 검사하지 않아야 하지만, 이 결과물을 include!() 매크로에 의해 현재 코드에 포함하기 때문에 clippy의 눈에 띄어서 문제가 되고 있는 것이다.

pub(crate) mod <모듈 이름> {
    // Include gRPC proto file.
    tonic::include_proto!("<proto 패키지 이름>");

    // Include pbjson-generated Serialize/Deserialize impls for the same type.
    include!(concat!(env!("OUT_DIR"), "/<생성된 proto 패키지 serde 파일>"));
} 

혹시나 이 문제에 대한 pbjon의 해결 패치가 있을까 해서 찾아 봤더니 2025년 12월 이후로는 버전 태그가 없었다.

결국 이 문제는 해결 하려면 3가지 정도의 해결 방법 있을 텐데,

  1. CI의 버전을 stable latest가 이닌 로컬 버전과 같은 1.94.1로 고정한다.
  2. 경고를 출력하더라도 실패로 보고 하지 않도록 clippy의 -D warning 파라미터를 제거한다.
  3. 경고를 출력하지 않도록 surpress한다.

이 중 3번을 적용하되 전체 범위가 아닌 include!() 구문에만 적용되도록 했다.

#[allow(unknown_lints)]
#[allow(clippy::useless_borrows_in_formatting)]
pub(crate) mod <모듈 이름> {
    // Include gRPC proto file.
    tonic::include_proto!("<proto 패키지 이름>");

    // Include pbjson-generated Serialize/Deserialize impls for the same type.
    include!(concat!(env!("OUT_DIR"), "/<생성된 proto 패키지 serde 파일>"));
}

#[allow(unknown_lints)]는 현재 버전의 clippy가 이해하지 못하는 lint feature가 있더라도 경고를 출력하지 말라는 의미이고, #[allow(clippy::useless_borrows_in_formatting)]가 바로 중복된 referrence를 발견하면 경고를 띄우는 해당 lint를 무시하도록 하는 디렉티브이다.

PyO3로 Rust code에서 Python module 사용하기

PyO3를 이용하면 Rust에서 Python을 호출하거나 반대로 Python에서 Rust를 호출하는 바인딩을 구현할 수 있다. 이 포스팅에서는 예전에 해봤던 Datumaro로 데이터셋을 detect하는 Python함수를 Rust로 호출하는 예제를 구현해 본다.

Python 의존설 설치

Python 관련한 의존성은 예전과 같이 Datumaro를 사용하는데 필요한 것들을 설치해 준다.

pip install 'datumaro[tf,tfds]' \
   tensorboardX \
   tensorflow-dataset \
   importlib_resources \
   nibabel

Rust 의존성 crates 설정

다음과 같은 crate들이 필요하다.

  • pyo3: PyO3 라이브러리
  • shellexpand: ~를 절대경로로 변환하는데 사용
  • tempfile: 압축 파일을 해제 해둘 임시공간 생성
  • zip, tar, flate2: 압축해제
cargo add pyo3 shellexpand tempfile zip tar flate2 

Rust 구현 코드

실행결과

Rust Debug – 10.9초

구현이 끝나고 돌려 봤을 때 조금 전다는 느낌이 있기는 했지만 모든 데이터셋들을 압축해제 하고 detect하는데 대략 10.9초 정도가 걸렸다.

Python vs. Rust Release

반면 Python은 3.5초 정도면 동일한 동작이 끝난다.

역시 바인딩을 위한 중간 레이어에서 뭘 많이 잡아 먹는 것일까? 하고 생각하다가 release 모드로 돌려 봤더니 결과가 확연히 좋아져서 2.5초 정도로 개선되었다.

Rust의 디버그 모드와 릴리즈 모드의 차이가 생각보다 크게 난다.

Datumaro를 이용한 dataset format 확인

Datumaro는 Intel에서 Opensource로 배포하는 Dataset 관리를 위한 프레임 워크이다. Dataset 간의 변환 등의 다양한 기능을 제공하는데, 이를 이용하면 주어진 dataset이 어떤 포맷인지도 쉽게 알 수 있기에 유용하다. 이 포스팅에서는 Datumaro를 설정하고 dataset의 포맷을 확인하는 방법을 알아본다.

Dependencies

이 포스팅에서는 datumaro에 포함된 datum의 dataset download 기능을 이용해서 다양한 형식의 dataset을 download 받을 수 있었는데, 이를 이용하려면 다음의 의존성이 만족해야 한다.

pip install 'datumaro[tf,tfds]' \
   tensorboardX \
   tensorflow-dataset \
   importlib_resources \
   nibabel

tfds는 TensorFlow project에서 관리하는 dataset 컬렉션이고 여기에서 곧바로 다운로드를 받아 올 수 있다. 문서 상에는 Kaggle도 지원하는 것처럼 되어 있기는 한데, 실제로는 다운로드 되지 않았다(Jul 2026 현재).

Dataset Download

의존성 설치가 완료된 다음에는 datum 명령어를 이용해서 다운로드 가능한 dataset의 목록을 볼 수 있다.

datum download tfds describe --report-format json

위의 예제 명령줄은 tfds로 부터 목록을 받아오는 것이며 전술 했듯, 현재 시점에서 kaggle은 아무 내용도 보여 주지 않는다.

출력되는 결과에는 dataset의 이름과 그것에 대한 세부 사항들이 표시되는데, 특정한 dataset을 받기 위해서는 datum downloadget 명령어를 사용하면 된다. 예를 들어 다운로드 받은 항목이 다음과 같이 표시되었다고 하면,

{
  "tfds:cifar10": {
    "default_output_format": "cifar",
    "description": "The CIFAR-10 dataset consists of 60000 32x32 colour images in 10 classes, with 6000 images per class. There are 50000 training images and 10000 test images.",
    "download_size": 170052171,
    "home_url": "https://www.tensorflow.org/datasets/catalog/cifar10",
    "human_name": "CIFAR-10",
    "num_classes": 10,
    "version": "3.0.2",
    "subsets": {
      "train": {
        "num_items": 50000
      },
      "test": {
        "num_items": 10000
      }
    }
  },
...
}

이 데이터셋 “tfds:cifar10”을 다운로드 받기 위해 dataset의 id를 명시해서 다음의 명령어를 수행하면 된다.

mkdir -p ~/Downloads/dataset
datum download tfds get -i tfds:cifar10 -o ~/Downloads/dataset/cifar10

Dataset format detection 예제

특정한 dataset의 형식을 알고자 한다면 datumaro.Dataset.detect() method의 path parameter에 dataset의 root directory를 넘겨주면 어떤 형식인지 str로 반환해 준다.

내 경우, dataset을 압축 포맷으로 저장해 두는 경우가 많아서, 압축파일을 임시 디렉토리에 풀고 해당 dataset의 format을 검사해서 출력하도록 작성했다.

실행결과

현재 다운로드가 가능한 tfds의 모든 format들과 내가 가지고 있던 dataset들의 format을 잘 detect 해 주었다. 다만, voc_2012 dataset은 하나 이상의 format으로 매치 되는 MultipleFormatsMatchError가 올려지고 있어서 이 경우에 대한 부가적인 처리가 필요할 것 같다. 예제 에서는 그냥 중복 매칭된 포맷들의 목록을 출력해 주었다.