Вступление

Приветствую, растиане, сегодня мы поговорим о сборке и публикации собственного крейта на crates.io.
Rust - open-source язык программирования, благодаря чему каждый может внести свой вклад в его развитие разными способами. Одним из таких способов является написание и публикация своего крейта. Крейт - это модульная единица кода, которая может использоваться другими разработчиками для создания своих программных решений.
В этой статье я расскажу, как написать свою библиотеку и опубликовать ее на crates.io на примере собственного проекта для работы с матрицами.

Дисклеймер

Автор статьи также учится программировать, поэтому в статье возможны(они есть) недочеты и ошибки, прошу отнестись с пониманием и поправить в комментариях.

Начнем с базы

Для написания своего крейта нам нужно, как ни странно, создать проект. Для этого открываем редактор кода или терминал, открываем нужную директорию и прописываем cargo init. После чего в папке с проектом появилось несколько файлов.Открываем файлик main.rs и видим следующий код:

//main.rs
fn main() {   
  println!("Hello, world!");
}

Круто, но скорее всего никто не захочет подключать это в свой проект), поэтому создадим еще парочку файлов: lib.rs и matrix2.rs. В matrix2.rs объявим структуру Matrix2

//matrix2.rs
#[derive(Debug)]
pub struct Matrix2<T: Clone + Copy> {
    pub(crate) rows: usize,
    pub(crate) columns: usize,
    pub(crate) elems: Vec<Vec<T>>,
}

При объявлении указываем модификатор доступа pub, чтобы объекты структуры можно было создавать вне этого файла, имплементируем для нее трейт Debug, чтобы можно было вывести ее содержимое в консоль. Также укажем для всех полей модификатор доступа pub(crate), что означает, что поля структуры будут видны везде внутри крейта, но не будут доступны пользователю. В файл lib.rs добавляем всего одну строку кода:

//lib.rs
pub mod matrix2;

Которая позволяет нам создавать объекты Matrix2 в main.rs файле. Но мы пока не можем их инициализировать, поэтому добавим метод new, принимающий в себя 4 значения матрицы:

//matrix2.rs
impl<T: Clone + Copy> Matrix2<T> {
    pub fn new(m1: T, m2: T, m3: T, m4: T) -> Matrix2<T> {
        Matrix2 {
            rows: 2,
            columns: 2,
            elems: vec![vec![m1, m2], vec![m3, m4]],
        }
    }
}

После этого надо немного переписать файл main.rs

//main.rs
extern crate hav;

use hav::matrix2::Matrix2;

fn main() {
    let m = Matrix2::new(1, 2, 3, 4);
    println!("{:?}", m);
}

Теперь мы можем собрать проект с помощью команды cargo build и запустить его с помощью cargo run. В консоли получаем:

Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target\debug\main.exe`
Matrix2 { rows: 2, columns: 2, elems: [[1, 2], [3, 4]] }

Matrix2 это и есть наша матрица размером 2 на 2 с элементами 1, 2, 3, 4.
Круто! Мы написали часть библиотеки, теперь можно залить ее на github, это понадобится для ее публикации.

Комментарии

Перед тем, как выложить крейт в открытый доступ, было бы неплохо написать к ней документацию. Это нужно, чтобы пользователю было проще разобраться с библиотекой.
Делается это с помощью написания ///

Например:

// matrix2.rs
/// Structure for matrix2
#[derive(Debug)]
pub struct Matrix2<T: Clone + Copy> {
    pub(crate) rows: usize,
    pub(crate) columns: usize,
    pub(crate) elems: Vec<Vec<T>>,
}

/// Creates new matrix2
impl<T: Clone + Copy> Matrix2<T> {
    pub fn new(m1: T, m2: T, m3: T, m4: T) -> Matrix2<T> {
        Matrix2 {
            rows: 2,
            columns: 2,
            elems: vec![vec![m1, m2], vec![m3, m4]],
        }
    }
}

Таким образом,с помощью ///, мы написали кусочек документации к нашему крейту
После этого можно выполнить команду cargo doc --open, это создаст страницу крейта в target директории, а флаг --open сразу откроет этот файл в браузере.

Открылась страница, и мы можем даже нажать на matrix2 и увидеть структуру Matrix2 с нашим комментарием.

Кликнем и на нее и увидим, помимо реализованных трейтов, описание метода new

Помимо модулей и структур в документацию добавятся и публичные функции из файла lib.rs :

// lib.rs
pub mod matrix2;

/// Hello from my crate!
pub fn print_hello() {
    println!("Hello, world!");
}

Еще можно добавить описание библиотеки с помощью //!

// lib.rs
//! # hav
//!
//! It's my crate!

/// Matrix2
pub mod matrix2;

/// Hello from my crate!
pub fn print_hello() {
    println!("Hello, world!");
}

Итак, мы научились документировать нашу библиотеку, пора и опубликовать ее!

Добавление метаданных

А нет, обманул, надо добавить данные о вашей библиотеке в .toml файл:

[package]
name = "hav"
version = "0.1.0"
edition = "2021"
description = ""
license = ""
homepage = ""
repository = ""
documentation = ""
readme = ""
categories = [""]
keywords = [""]

[dependencies]

После этого можно уже приступать к последнему шагу.

Публикация

Для публикации достаточно просто написать команду cargo publish
Также можно указать флаги, например --no-deps, чтобы не публиковать зависимости вашего крейта. Полный список флагов можно найти тут.
Выполняем команду и что, неужели все? Конечно нет.
Для публикации на crates.io, как ни странно, там надо зарегестрироваться, а точнее войти через github. Дальше переходим по этой ссылке и получаем свой ключ API.
Выполняем команду cargo login <your_key> .
Теперь пишем cargo publish и все! Наша библиотека попадает на crates.io, а через некоторое время на сайте https://docs.rs/ появляется документация

Вывод

В этой статье мы научились создавать свой крейт на яп Rust и публиковать его на crates.io.

Опубликованную мной библиотеку и ее исходный код можно посмотреть тут.

Всем спасибо за уделенное время, надеюсь этот не очень подробный гайд кому-то поможет!

Комментарии (5)


  1. Vest
    06.07.2023 06:11

    Глядя на такое огромное количество заброшенных крейтов на crates.io, мне даже становится жалко экосистему раста. Порядка 1300 крейтов с ключевым словом matrix. Самый популярный обновлялся в 2018 году.

    Уже давно поговаривают о том, что крейты постигнет судьба npm-помойки.

    Извините, если вас задел.


    1. Gorthauer87
      06.07.2023 06:11
      +1

      Там есть каталоги типа awesome Rust, по которым можно найти хорошие крейты, да и поиск тоже неплохо справляется. А что будет тонна мусора, это неизбежно в свободной экосистеме.


      1. vtvz_ru
        06.07.2023 06:11

        Мне нравится подход phpшного packagist, где у каждого пакета не только свое название, но и неймспейс, соответствующий юзернейму. Ну или как у докер-хаба сделано, где только проверенные образы не имеют префикса. Никакой помойки нет, и пакеты одного автора в одной куче лежат.
        Мне казалось, что Раст пойдет по тому же пути. Но он пошел дорогой npm.


  1. domix32
    06.07.2023 06:11
    +2

    Относительно недавно появился ещё cargo-release позволяющий в том числе и публикацию на crates.io. Интеграция с CI включена.


    1. DaniilUbica Автор
      06.07.2023 06:11

      Не знал, спасибо за информацию