Publicando un Crate a Crates.io
Hasta ahora, hemos usado paquetes de crates.io como dependencias de nuestro proyecto, pero también puedes compartir tu código con otras personas publicando tus propios paquetes. El registro de paquetes en crates.io distribuye el código fuente de tus paquetes, por lo que aloja principalmente código que es de código abierto.
Rust y Cargo tienen características que hacen que tu paquete publicado sea más fácil de encontrar y usar. Hablaremos sobre algunas de estas características a continuación y luego explicaremos cómo publicar un paquete.
Haciendo comentarios de documentación útiles
Documentar adecuadamente tus paquetes ayudará a otros usuarios a saber cómo y
cuándo usarlos, por lo que vale la pena invertir el tiempo para escribir
documentación. En el Capítulo 3, discutimos cómo comentar el código Rust usando
dos barras diagonales, //
. Rust también tiene un tipo particular de comentario
para la documentación, conocido convenientemente como un comentario de
documentación, que generará documentación HTML. El HTML muestra el contenido
de los comentarios de documentación para los elementos de API públicos
destinados a programadores interesados en saber cómo usar tu paquete en
oposición a cómo se implementa tu paquete.
Los comentarios de documentación usan tres barras diagonales, ///
, en lugar
de dos y admiten la notación Markdown para formatear el texto. Coloca los
comentarios de documentación justo antes del elemento que están documentando.
El Listado 14-1 muestra comentarios de documentación para una función add_one
en un crate llamado my_crate
.
Filename: src/lib.rs
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
Listing 14-1: Un comentario de documentación para una función
Aquí, damos una descripción de lo que hace la función add_one
, comenzamos una
sección con el encabezado Examples
y luego proporcionamos código que
demuestra cómo usar la función add_one
. Podemos generar la documentación HTML
de este comentario de documentación ejecutando cargo doc
. Este comando ejecuta
la herramienta rustdoc
distribuida con Rust y coloca la documentación HTML
generada en el directorio target/doc.
Por conveniencia, ejecutar cargo doc --open
generará el HTML para la
documentación de tu crate actual (así como la documentación para todas las
dependencias de tu crate) y abrirá el resultado en un navegador web. Navega
hasta la función add_one
y verás cómo se renderiza el texto en los comentarios
de documentación, como se muestra en la Figura 14-1:

Figura 14-1: documentación en HTML para la función
add_one
Secciones comúnmente usadas
Hemos usado el encabezado de Markdown # Examples
en el Listado 14-1 para crear
una sección en el HTML con el título "Examples". Aquí hay algunas otras
secciones que los autores de crates comúnmente usan en su documentación:
- Panics: Los escenarios en los que la función documentada podría entrar en panic. Los llamadores de la función que no quieren que sus programas entren en panic deben asegurarse de no llamar a la función en estas situaciones.
- Errores: Si la función devuelve un
Result
, describir los tipos de errores que podrían ocurrir y qué condiciones podrían hacer que esos errores se devuelvan puede ser útil para los llamadores para que puedan escribir código para manejar los diferentes tipos de errores de diferentes maneras. - Seguridad: Si la función es
unsafe
de llamar (discutimos unsafe en el Capítulo 19), debería haber una sección que explique por qué la función es insegura y cubra las invariantes que la función espera que los llamadores mantengan.
La mayoría de los comentarios de documentación no necesitan todas estas secciones, pero esta es una buena lista de verificación para recordar los aspectos del código que los usuarios estarán interesados en saber.
Comentarios de documentacion como Tests
Agregar bloques de código de ejemplo en tus comentarios de documentación puede
ayudar a demostrar cómo usar tu biblioteca, y hacerlo tiene una ventaja
adicional: ¡ejecutar cargo test
ejecutará los ejemplos de código en tu
documentación como pruebas! Nada es mejor que la documentación con ejemplos.
Pero nada es peor que los ejemplos que no funcionan porque el código ha cambiado
desde que se escribió la documentación. Si ejecutamos cargo test
con la
documentación para la función add_one
del Listado 14-1, veremos una sección en
los resultados de la prueba como esta:
Doc-tests my_crate
running 1 test
test src/lib.rs - add_one (line 5) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s
¡Ahora si cambiamos la función o el ejemplo para que el assert_eq!
en el
ejemplo entre en pánico y ejecutamos cargo test
nuevamente, veremos que los
doc tests capturan que el ejemplo y el código están fuera de sincronización
entre sí!
Comentando items contenidos
El estilo de comentario de doc //!
agrega documentación al item que contiene
los comentarios en lugar de a los items que siguen a los comentarios.
Normalmente, usamos estos comentarios de documentación dentro del archivo raíz
del crate (src/lib.rs por convención) o dentro de un módulo para documentar el
crate o el módulo en su conjunto.
Por ejemplo, para agregar documentación que describe el propósito del crate
my_crate
que contiene la función add_one
, agregamos comentarios de
documentación que comienzan con //!
al principio del archivo src/lib.rs,
como se muestra en el Listado 14-2:
Nombre de archivo: src/lib.rs
//! # My Crate
//!
//! `my_crate` is a collection of utilities to make performing certain
//! calculations more convenient.
/// Adds one to the number given.
// --snip--
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
Listado 14-2: Documentación para el crate my_crate
como
un todo
Observa que no hay ningún código después de la última línea que comienza con
//!
. Debido a que comenzamos los comentarios con //!
en lugar de ///
,
estamos documentando el item que contiene este comentario en lugar de un item
que sigue a este comentario. En este caso, ese item es el archivo src/lib.rs,
que es el crate root. Estos comentarios describen todo el crate.
Cuando ejecutamos cargo doc --open
ahora, veremos la documentación para el
crate my_crate
en lugar de la documentación para la función add_one
, como
se muestra en la Figura 14-2:

Figura 14-2: Documentación renderizada para my_crate
,
incluido el comentario que describe el crate como un todo
Los comentarios de documentación dentro de los items son útiles para describir crates y módulos en particular. Úsalos para explicar el propósito general del contenedor para ayudar a tus usuarios a comprender la organización del crate.
Exportando una API publica conveniente con pub use
La estructura de tu API pública es una consideración importante al publicar un crate. Las personas que usan tu crate están menos familiarizadas con la estructura que tú y podrían tener dificultades para encontrar las piezas que desean usar si tu crate tiene una gran jerarquía de módulos.
En el Capítulo 7, cubrimos cómo hacer que los items sean públicos usando la
palabra clave pub
y traer items a un scope con la palabra clave use
.
Sin embargo, la estructura que tiene sentido para ti mientras desarrollas un
crate puede que no sea muy conveniente para tus usuarios. Es posible que desees
organizar tus structs en una jerarquía que contenga varios niveles, pero luego
las personas que desean usar un tipo que has definido profundamente en la
jerarquía podrían tener problemas para descubrir que ese tipo existe. También
podrían estar molestos por tener que ingresar use
my_crate::some_module::another_module::UsefulType;
en lugar de use
my_crate::UsefulType;
.
Las buenas noticias son que si la estructura no es conveniente para que otros
la usen desde otra biblioteca, no tienes que reorganizar tu organización
interna: en su lugar, puedes reexportar items para hacer una estructura pública
que sea diferente de tu estructura privada usando pub use
. Reexportar toma un
item público en una ubicación y lo hace público en otra ubicación, como si se
definiera en la otra ubicación en su lugar.
Por ejemplo, supongamos que creamos una biblioteca llamada art
para modelar
conceptos artísticos. Dentro de esta biblioteca hay dos módulos: un módulo
kinds
que contiene dos enums llamados PrimaryColor
y SecondaryColor
y un
módulo utils
que contiene una función llamada mix
, como se muestra en el
Listado 14-3:
Nombre de archivo: src/lib.rs
//! # Art
//!
//! A library for modeling artistic concepts.
pub mod kinds {
/// The primary colors according to the RYB color model.
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// The secondary colors according to the RYB color model.
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
use crate::kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
// --snip--
unimplemented!();
}
}
Listado 14-3: Una biblioteca llamada art
con items
organizados en los módulos kinds
y utils
La Figura 14-3 muestra cómo se vería la página frontal de la documentación para
este crate generada por cargo doc
:

Figure 14-3: Página principal de la documentación de art
que enumera los módulos kinds
y utils
Nota que los tipos PrimaryColor
y SecondaryColor
no están listados en la
página principal. Tampoco lo está la función mix
. Para verlos, tendríamos que
hacer clic en kinds
y utils
.
Otro crate que depende de esta biblioteca necesitaría declarar un use
que
traigan los items de art
al scope, especificando la estructura de módulos
actualmente definida. El Listado 14-4 muestra un ejemplo de un crate que usa
los items PrimaryColor
y mix
del crate art
:
Nombre de archivo: src/main.rs
use art::kinds::PrimaryColor;
use art::utils::mix;
fn main() {
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
Listado 14-4: Un crate que utiliza los items del crate
art
con su estructura interna exportada
El autor del código en el Listado 14-4, que usa el crate art
, tuvo que
averiguar que PrimaryColor
está en el módulo kinds
y mix
está en el
módulo utils
. La estructura de módulos del crate art
es más relevante para
los desarrolladores que trabajan en el crate art
que para aquellos que lo
usan. La estructura interna no contiene ninguna información útil para alguien
que intenta comprender cómo usar el crate art
, sino que causa confusión
porque los desarrolladores que lo usan tienen que averiguar dónde buscar y
deben especificar los nombres de módulo en las declaraciones use
.
Para remover la estructura interna de la API pública, podemos modificar el
código del crate art
en el Listado 14-3 para agregar declaraciones pub use
para reexportar los items en el nivel superior, como se muestra en el Listado
14-5:
Nombre de archivo: src/lib.rs
//! # Art
//!
//! A library for modeling artistic concepts.
pub use self::kinds::PrimaryColor;
pub use self::kinds::SecondaryColor;
pub use self::utils::mix;
pub mod kinds {
// --snip--
/// The primary colors according to the RYB color model.
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// The secondary colors according to the RYB color model.
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
// --snip--
use crate::kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
SecondaryColor::Orange
}
}
Listado 14-5: Agregando declaraciones pub use
para
re-exportar items
La documentación de la API que cargo doc
genera para este crate ahora
listará y enlazará los reexports en la página principal, como se muestra en la
Figura 14-4, haciendo que los tipos PrimaryColor
y SecondaryColor
y la
función mix
sean más fáciles de encontrar.

Figura 14-4: La página principal de la documentación para
art
que lista las re-exportaciones
Los usuarios del crate art
aún pueden ver y usar la estructura interna del
Listado 14-3 como se demuestra en el Listado 14-4, o pueden usar la estructura
más conveniente del Listado 14-5, como se muestra en el Listado 14-6:
Nombre de archivo: src/main.rs
use art::mix;
use art::PrimaryColor;
fn main() {
// --snip--
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
Listado 14-6: Un programa que utiliza los items
reexportados del crate art
En casos donde hay muchos módulos anidados, reexportar los tipos en el nivel
superior con pub use
puede hacer una diferencia significativa en la
experiencia de las personas que usan el crate. Otro uso común de pub use
es
reexportar definiciones de una dependencia en el crate actual para hacer que
las definiciones de ese crate sean parte de la API pública de su crate.
Crear una estructura de API pública es más un arte que una ciencia, y puedes
iterar para encontrar la API que funcione mejor para tus usuarios. Elegir pub use
te da flexibilidad en cómo estructuras tu crate internamente y desacopla
esa estructura interna de lo que presentas a tus usuarios. Mira algo del código
de los crates que has instalado para ver si su estructura interna difiere de su
API pública.
Configurando una cuenta de Crates.io
Antes de que puedas publicar cualquier crate, necesitas crear una cuenta en
crates.io y obtener un token de API. Para
hacerlo, visita la página de inicio en
crates.io e inicia sesión a través de una
cuenta de GitHub. (La cuenta de GitHub es actualmente un requisito, pero el
sitio podría admitir otras formas de crear una cuenta en el futuro). Una vez
que hayas iniciado sesión, visita la configuración de tu cuenta en
https://crates.io/me/ y recupera tu
clave de API. Luego ejecuta el comando cargo login
y pega tu clave de la API,
cuando se solicitad, como se muestra a continuación:
$ cargo login
abcdefghijklmnopqrstuvwxyz012345
Este comando informará a Cargo de tu token de API y lo almacenará localmente en ~/.cargo/credentials. Ten en cuenta que este token es un secreto: no lo compartas con nadie. Si lo compartes con alguien por cualquier motivo, debes revocarlo y generar un nuevo token en crates.io.
Agregando metadata a un nuevo crate
Supongamos que tienes un crate que deseas publicar. Antes de publicarlo,
necesitarás agregar algunos metadatos en la sección [package]
del archivo
Cargo.toml del crate.
Tu crate necesitará un nombre único. Mientras trabajas en un crate localmente,
puedes nombrar un crate como quieras. Sin embargo, los nombres de los crates en
crates.io se asignan por orden de llegada.
Una vez que se toma un nombre de crate, nadie más puede publicar un crate con
ese nombre. Antes de intentar publicar un crate, busca el nombre que deseas
usar. Si el nombre ha sido usado, deberás encontrar otro nombre y editar el
campo name
en el archivo Cargo.toml bajo la sección [package]
para usar
el nuevo nombre para publicar, como se muestra a continuación:
Nombre de archivo: Cargo.toml
[package]
name = "guessing_game"
Incluso si has elegido un nombre único, cuando ejecutes cargo publish
para
publicar el crate en este punto, obtendrás una advertencia y luego un error:
$ cargo publish
Updating crates.io index
warning: manifest has no description, license, license-file, documentation, homepage or repository.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
--snip--
error: failed to publish to registry at https://crates.io
Caused by:
the remote server responded with an error: missing or empty metadata fields: description, license. Please see https://doc.rust-lang.org/cargo/reference/manifest.html for how to upload metadata
Estos errores se deben a que te faltan algunos datos cruciales: se requiere una
descripción y una licencia para que las personas sepan qué hace tu crate y
bajo qué términos pueden usarlo. En Cargo.toml, agrega una descripción que
sea solo una o dos oraciones, porque aparecerá con tu crate en los resultados
de búsqueda. Para el campo license
, debes dar un valor de identificador de
licencia. La Linux Foundation’s Software Package Data Exchange (SPDX)
enumera los identificadores que puedes usar para este valor. Por ejemplo, para
especificar que has licenciado tu crate usando la Licencia MIT, agrega el
identificador MIT
:
Nombre de archivo: Cargo.toml
[package]
name = "guessing_game"
license = "MIT"
Si tu deseas especificar una licencia que no aparece en el SPDX, necesitas
colocar el texto de esa licencia en un archivo, incluir el archivo en tu
proyecto y luego usar license-file
para especificar el nombre de ese archivo
en lugar de usar la key license
.
La orientación sobre qué licencia es apropiada para tu proyecto está fuera del
alcance de este libro. Muchas personas en la comunidad de Rust licencian sus
proyectos de la misma manera que Rust, usando una licencia dual de MIT OR Apache-2.0
. Esta práctica demuestra que también puedes especificar múltiples
identificadores de licencia separados por OR
para tener múltiples licencias
para tu proyecto.
Con un nombre único, la versión, una descripción y una licencia agregados, el archivo Cargo.toml para un proyecto que está listo para publicar podría verse así:
Nombre de archivo: Cargo.toml
[package]
name = "guessing_game"
version = "0.1.0"
edition = "2021"
description = "A fun game where you guess what number the computer has chosen."
license = "MIT OR Apache-2.0"
[dependencies]
La documentación de Cargo describe otros metadatos que puedes especificar para asegurarte de que otros puedan descubrir y usar tu crate más fácilmente.
Publicando en Crates.io
Ahora que has creado una cuenta, guardado tu token de API, elegido un nombre para tu crate y especificado los metadatos requeridos, ¡estás listo para publicar! Publicar un crate carga una versión específica en crates.io para que otros la usen.
Ten cuidado, porque una publicación es permanente. La versión nunca se puede sobrescribir y el código no se puede eliminar. Uno de los principales objetivos de crates.io es actuar como un archivo permanente de código para que las compilaciones de todos los proyectos que dependen de crates de crates.io sigan funcionando. Permitir la eliminación de versiones haría imposible cumplir ese objetivo. Sin embargo, no hay límite en la cantidad de versiones de crate que puedes publicar.
Ejecuta el comando cargo publish
otra vez. Esta vez, debería tener éxito:
$ cargo publish
Updating crates.io index
Packaging guessing_game v0.1.0 (file:///projects/guessing_game)
Verifying guessing_game v0.1.0 (file:///projects/guessing_game)
Compiling guessing_game v0.1.0
(file:///projects/guessing_game/target/package/guessing_game-0.1.0)
Finished dev [unoptimized + debuginfo] target(s) in 0.19s
Uploading guessing_game v0.1.0 (file:///projects/guessing_game)
¡Felicidades! Ahora has compartido tu código con la comunidad de Rust y cualquiera puede agregar tu crate como una dependencia de su proyecto.
Publicando una Nueva Versión de un Crate Existente
Cuando hayas realizado cambios en tu crate y estés listo para publicar una
nueva versión, cambia el valor version
especificado en tu archivo
Cargo.toml y vuelve a publicar. Usa las
reglas de versionado semántico para decidir cuál es el siguiente
número de versión apropiado en función de los tipos de cambios que hayas
realizado. Luego, ejecuta cargo publish
para cargar la nueva versión.
Deprecando Versiones de Crates.io con cargo yank
Aunque no puedes eliminar versiones anteriores de un crate, puedes evitar que cualquier proyecto futuro las agregue como una nueva dependencia. Esto es útil cuando una versión de crate está rota por una razón u otra. En tales situaciones, Cargo admite yanking una versión de crate.
Hacer un yank a una versión impide que nuevos proyectos dependan de esa versión, pero permite que todos los proyectos existentes que dependen de ella continúen. Esencialmente, un yank significa que todos los proyectos con un Cargo.lock no se romperán y que cualquier Cargo.lock futuro generado no usará la versión yanked.
Para hacer un yank de una versión de un crate, en el directorio del crate que
has publicado previamente, ejecuta cargo yank
y especifica qué versión
deseas yank. Por ejemplo, si hemos publicado un crate llamado
guessing_game
versión 1.0.1 y queremos yank la versión, en el directorio
del proyecto para guessing_game
ejecutaríamos:
$ cargo yank --vers 1.0.1
Updating crates.io index
Yank guessing_game@1.0.1
Al agregar --undo
al comando, también puedes deshacer un yank y permitir
que los proyectos vuelvan a depender de una versión:
$ cargo yank --vers 1.0.1 --undo
Updating crates.io index
Unyank guessing_game@1.0.1
Un yank no borra ningún código. No puede, por ejemplo, eliminar secretos cargados accidentalmente. Si eso sucede, debes restablecer esos secretos inmediatamente.