Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewsonin authored and Andrew Sonin committed May 15, 2024
0 parents commit 1bc3905
Show file tree
Hide file tree
Showing 11 changed files with 989 additions and 0 deletions.
75 changes: 75 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

env:
CARGO_TERM_COLOR: always
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1
RUST_LOG: lazy_ref

jobs:
fmt:
name: "Fmt"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: rustup show active-toolchain -v
- run: rustup component add rustfmt
- run: cargo fmt --version
- run: cargo fmt -- --check

build:
name: "Build"
needs: fmt
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Build project
run: cargo build --all-targets --all-features

docs:
name: "Docs"
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Build Documentation
run: cargo doc --all --no-deps --release

clippy:
name: "Clippy"
needs: fmt
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Add clippy
run: rustup component add clippy
- name: Clippy version
run: cargo clippy --version
- name: Run clippy
run: cargo clippy
- name: Run clippy with all features
run: cargo clippy --all-targets --all-features
- name: Run clippy on tests
run: cargo clippy --tests --all-targets --all-features

tests:
name: "Tests"
needs: [build, clippy]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run tests
run: cargo test
- name: Run tests with all features
run: cargo test --all-features
- name: Run tests with all features in release mode
run: cargo test --all-features --release
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# macOS Finder files
.DS_Store

# JetBrains files
.idea/
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

<!-- next-header -->

## [1.0.0] - 2024-05-15
### Added
- `PrintableIter`
- `PrintableTuple`

<!-- next-url -->
[1.0.0]: https://github.com/andrewsonin/lazy_ref/releases/tag/v1.0.0
31 changes: 31 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "printable"
version = "0.1.0"
authors = ["Andrew Sonin <sonin.cel@yandex.ru>"]
categories = ["value-formatting"]
description = "Provides `std::fmt::Display` wrapper for iterators and tuples."
keywords = ["printable", "formatting", "display"]
documentation = "https://docs.rs/printable/"
homepage = "https://github.com/andrewsonin/printable"
repository = "https://github.com/andrewsonin/printable"
license = "MIT"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

[lints.rust]
rust_2018_idioms = { level = "warn", priority = 1 }
unreachable_pub = "warn"
missing_docs = "warn"
missing_debug_implementations = "warn"

[lints.clippy]
undocumented_unsafe_blocks = "warn"
pedantic = { level = "warn", priority = 1 }

[features]
# May violate backward compatibility and lead to compilation failure
# even if the major semver versions of the underlying crates aren't updated.
unstable-assert-no-drop = []
25 changes: 25 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Copyright (c) 2024 printable contributors

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# printable

_Provides `std::fmt::Display` wrapper for iterators and tuples._

[![Crates.io][crates-badge]][crates-url]
[![Documentation][docs-badge]][docs-url]
[![MIT licensed][mit-badge]][mit-url]
[![Build Status][actions-badge]][actions-url]

[crates-badge]: https://img.shields.io/crates/v/printable.svg
[crates-url]: https://crates.io/crates/printable
[docs-badge]: https://img.shields.io/docsrs/printable
[docs-url]: https://docs.rs/printable
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
[mit-url]: https://github.com/andrewsonin/printable/blob/main/LICENSE
[actions-badge]: https://github.com/andrewsonin/printable/actions/workflows/ci.yml/badge.svg
[actions-url]: https://github.com/andrewsonin/printable/actions/workflows/ci.yml

## Usage

Displaying iterators.

```rust
use printable::prelude::PrintableIter;

let v = vec![1, 2, 3];
assert_eq!(format!("{}", v.iter().printable()), "[1, 2, 3]");
```

Displaying tuples.

```rust
use printable::prelude::PrintableTuple;

let v = (1, "2", 3.0);
assert_eq!(format!("{}", v.printable()), "[1, 2, 3]");
```

## Features

* __`unstable-assert-no-drop`__

Enables compile-time assertions that the iterators used don't own any resource.

### Warning
May violate backward compatibility and lead to compilation failure
even if the major semver versions of the underlying crates aren't
updated.

This may happen due to the following factors:
- The `std::mem::needs_drop` documentation does not guarantee
stability.
- The fact that the iterator type, which can be declared in a third-party
crate, started owning a resource doesn't require increasing the major
version of this crate.
6 changes: 6 additions & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
edition = "2021"
merge_derives = false
imports_granularity = "Crate"
normalize_comments = true
reorder_impl_items = false
wrap_comments = true
111 changes: 111 additions & 0 deletions src/iter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use std::fmt::{Display, Formatter};

use crate::wrapper::{DisplayWithSep, PrintableWrapper};

/// Wraps iterators into [`PrintableWrapper`].
///
/// # Warning
///
/// Avoid creating [`PrintableWrapper`] from resource-owning iterators such as
/// [`std::vec::IntoIter`], since they would clone the owned data or perform
/// other heavy operations every time [`Display::fmt`] is called.
///
/// To statically ensure that you don't use resource-owning iterators in such a
/// context, enable the `unstable-assert-no-drop` feature. However, this
/// approach has serious drawbacks. See the description of this feature in the
/// documentation.
///
/// # Examples
///
/// ```rust
/// use printable::prelude::PrintableIter;
///
/// let v = vec![1, 2, 3];
/// assert_eq!(format!("{}", v.iter().printable()), "[1, 2, 3]");
///
/// let v: Vec<usize> = vec![1];
/// assert_eq!(format!("{}", v.iter().printable()), "[1]");
///
/// let v: Vec<usize> = vec![];
/// assert_eq!(format!("{}", v.iter().printable()), "[]");
/// ```
pub trait PrintableIter: Iterator + Clone
where
Self::Item: Display,
{
/// Compile-time assertion that `Self` doesn't own any resource.
///
/// # Warning
///
/// May violate backward compatibility and lead to compilation failure
/// even if the major semver versions of the underlying crates aren't
/// updated.
///
/// This may happen due to the following factors:
/// - The [`std::mem::needs_drop`] documentation does not guarantee
/// stability.
/// - The fact that the `Self` type, which can be declared in a third-party
/// crate, started owning a resource doesn't require increasing the major
/// version of this crate.
#[cfg(feature = "unstable-assert-no-drop")]
const NO_DROP_CHECK: () = { assert!(!std::mem::needs_drop::<Self>()) };

/// Wraps custom iterator into [`PrintableWrapper`].
#[inline]
fn printable(
self,
) -> PrintableWrapper<&'static str, &'static str, &'static str, IterHandler<Self>> {
#[cfg(feature = "unstable-assert-no-drop")]
let _ = Self::NO_DROP_CHECK;
PrintableWrapper {
inner: IterHandler(self),
sep: ", ",
left_bound: "[",
right_bound: "]",
}
}
}

impl<T> PrintableIter for T
where
T: Iterator + Clone,
T::Item: Display,
{
}

impl<T> From<T>
for PrintableWrapper<&'static str, &'static str, &'static str, IterHandler<T::IntoIter>>
where
T: IntoIterator,
T::Item: Display,
T::IntoIter: Clone,
{
#[inline]
fn from(value: T) -> Self {
value.into_iter().printable()
}
}

/// Handler for iterators used inside the [`PrintableWrapper`].
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct IterHandler<T>(T);

impl<T> DisplayWithSep for IterHandler<T>
where
T: Iterator + Clone,
T::Item: Display,
{
#[inline]
fn fmt(&self, f: &mut Formatter<'_>, sep: &impl Display) -> std::fmt::Result {
let mut iter = self.0.clone();
if let Some(v) = iter.next() {
v.fmt(f)?;
for v in iter {
sep.fmt(f)?;
v.fmt(f)?;
}
};
Ok(())
}
}
15 changes: 15 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![doc = include_str!("../README.md")]

#![allow(clippy::module_name_repetitions)]

/// Implements [`Display`](std::fmt::Display) wrapper for iterators.
pub mod iter;
/// Implements [`Display`](std::fmt::Display) wrapper for tuples.
pub mod tuple;
/// Implements [`PrintableWrapper`](wrapper::PrintableWrapper).
pub mod wrapper;

/// Crate's prelude.
pub mod prelude {
pub use crate::{iter::PrintableIter, tuple::PrintableTuple, wrapper::PrintableWrapper};
}
Loading

0 comments on commit 1bc3905

Please sign in to comment.