<commit_before>use azure::core::errors::AzureError;
use azure::core::incompletevector::IncompleteVector;
use azure::core::{
    ClientRequestIdOption, ClientRequestIdSupport, ClientRequired, ContainerNameRequired, ContainerNameSupport, DelimiterOption,
    DelimiterSupport, IncludeCopyOption, IncludeCopySupport, IncludeDeletedOption, IncludeDeletedSupport, IncludeListOptions,
    IncludeMetadataOption, IncludeMetadataSupport, IncludeSnapshotsOption, IncludeSnapshotsSupport, IncludeUncommittedBlobsOption,
    IncludeUncommittedBlobsSupport, NextMarkerSupport, No, PrefixOption, PrefixSupport, TimeoutOption, TimeoutSupport, ToAssign, Yes,
};
use azure::storage::blob::requests::ListBlobBuilder;
use azure::storage::blob::Blob;
use azure::storage::client::Client;
use futures::prelude::*;
use futures::stream;
use std::marker::PhantomData;

#[derive(Debug, Clone)]
pub struct ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    client: &'a Client,
    p_container_name: PhantomData<ContainerNameSet>,
    container_name: Option<&'a str>,
    client_request_id: Option<&'a str>,
    timeout: Option<u64>,
    prefix: Option<&'a str>,
    delimiter: Option<&'a str>,
    include_snapshots: bool,
    include_metadata: bool,
    include_uncommitted_blobs: bool,
    include_copy: bool,
    include_deleted: bool,
}

impl<'a> ListBlobStreamBuilder<'a, No> {
    #[inline]
    pub(crate) fn new(client: &'a Client) -> ListBlobStreamBuilder<'a, No> {
        ListBlobStreamBuilder {
            client,
            p_container_name: PhantomData {},
            container_name: None,
            client_request_id: None,
            timeout: None,
            prefix: None,
            delimiter: None,
            include_snapshots: false,
            include_metadata: false,
            include_uncommitted_blobs: false,
            include_copy: false,
            include_deleted: false,
        }
    }
}

impl<'a, ContainerNameSet> ClientRequired<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn client(&self) -> &'a Client {
        self.client
    }
}

impl<'a> ContainerNameRequired<'a> for ListBlobStreamBuilder<'a, Yes> {
    #[inline]
    fn container_name(&self) -> &'a str {
        self.container_name.unwrap()
    }
}

impl<'a, ContainerNameSet> ClientRequestIdOption<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn client_request_id(&self) -> Option<&'a str> {
        self.client_request_id
    }
}

impl<'a, ContainerNameSet> TimeoutOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn timeout(&self) -> Option<u64> {
        self.timeout
    }
}

impl<'a, ContainerNameSet> PrefixOption<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn prefix(&self) -> Option<&'a str> {
        self.prefix
    }
}

impl<'a, ContainerNameSet> DelimiterOption<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn delimiter(&self) -> Option<&'a str> {
        self.delimiter
    }
}

impl<'a, ContainerNameSet> IncludeSnapshotsOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn include_snapshots(&self) -> bool {
        self.include_snapshots
    }
}

impl<'a, ContainerNameSet> IncludeMetadataOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn include_metadata(&self) -> bool {
        self.include_metadata
    }
}

impl<'a, ContainerNameSet> IncludeUncommittedBlobsOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn include_uncommitted_blobs(&self) -> bool {
        self.include_uncommitted_blobs
    }
}

impl<'a, ContainerNameSet> IncludeCopyOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn include_copy(&self) -> bool {
        self.include_copy
    }
}

impl<'a, ContainerNameSet> IncludeDeletedOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn include_deleted(&self) -> bool {
        self.include_deleted
    }
}

impl<'a, ContainerNameSet> ContainerNameSupport<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, Yes>;

    #[inline]
    fn with_container_name(self, container_name: &'a str) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: Some(container_name),
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> ClientRequestIdSupport<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_client_request_id(self, client_request_id: &'a str) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: Some(client_request_id),
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> TimeoutSupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_timeout(self, timeout: u64) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: Some(timeout),
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> PrefixSupport<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_prefix(self, prefix: &'a str) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: Some(prefix),
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> DelimiterSupport<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_delimiter(self, delimiter: &'a str) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: Some(delimiter),
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> IncludeSnapshotsSupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_include_snapshots(self) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: true,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> IncludeMetadataSupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_include_metadata(self) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: true,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> IncludeUncommittedBlobsSupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_include_uncommitted_blobs(self) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: true,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> IncludeCopySupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_include_copy(self) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: true,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> IncludeDeletedSupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_include_deleted(self) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: true,
        }
    }
}

// methods callable regardless
impl<'a, ContainerNameSet> ListBlobStreamBuilder<'a, ContainerNameSet> where ContainerNameSet: ToAssign {}

// this empty trait is required in order to use IncludeListOptions methods. No duck typing, sorry
// :(
impl<'a> IncludeListOptions for ListBlobStreamBuilder<'a, Yes> {}

enum ContinuationState {
    Start,
    Next(Option<String>),
}

impl<'a> ListBlobStreamBuilder<'a, Yes> {
    #[inline]
    pub fn finalize(self) -> impl Stream<Item = Vec<Blob>, Error = AzureError> {
        let container_name = self.container_name().to_owned();

        let client_request_id = self.client_request_id.map(|v| v.to_owned());
        let timeout = self.timeout.to_owned();
        let prefix = self.prefix.map(|v| v.to_owned());
        let delimiter = self.delimiter.map(|v| v.to_owned());
        let include_snapshots = self.include_snapshots;
        let include_metadata = self.include_metadata;
        let include_uncommitted_blobs = self.include_uncommitted_blobs;
        let include_copy = self.include_copy;
        let include_deleted = self.include_deleted;

        let client = self.client().clone();

        stream::unfold(ContinuationState::Start, move |cont_token| {
            let marker = match cont_token {
                ContinuationState::Start => None,
                ContinuationState::Next(Some(marker)) => Some(marker),
                ContinuationState::Next(None) => return None,
            };

            let mut req = ListBlobBuilder::new(&client).with_container_name(&container_name);

            if let Some(ref marker) = &marker {
                req = req.with_next_marker(&*marker);
            }
            if let Some(ref client_request_id) = &client_request_id {
                req = req.with_client_request_id(client_request_id);
            }
            if let Some(timeout) = timeout {
                req = req.with_timeout(timeout);
            }
            if let Some(ref prefix) = &prefix {
                req = req.with_prefix(prefix);
            }
            if let Some(ref delimiter) = &delimiter {
                req = req.with_delimiter(delimiter);
            }

            if include_snapshots {
                req = req.with_include_snapshots();
            }
            if include_metadata {
                req = req.with_include_metadata();
            }
            if include_uncommitted_blobs {
                req = req.with_include_uncommitted_blobs();
            }
            if include_copy {
                req = req.with_include_copy();
            }
            if include_deleted {
                req = req.with_include_deleted();
            }

            let req = req.finalize();
            Some(req.map(move |response| {
                let IncompleteVector { token, vector } = response.incomplete_vector;
                (vector, ContinuationState::Next(token))
            }))
        })
    }
}
<commit_msg>convert stream of Vec<Blob> into stream of blobs for list_blobs<commit_after>use azure::core::errors::AzureError;
use azure::core::incompletevector::IncompleteVector;
use azure::core::{
    ClientRequestIdOption, ClientRequestIdSupport, ClientRequired, ContainerNameRequired, ContainerNameSupport, DelimiterOption,
    DelimiterSupport, IncludeCopyOption, IncludeCopySupport, IncludeDeletedOption, IncludeDeletedSupport, IncludeListOptions,
    IncludeMetadataOption, IncludeMetadataSupport, IncludeSnapshotsOption, IncludeSnapshotsSupport, IncludeUncommittedBlobsOption,
    IncludeUncommittedBlobsSupport, NextMarkerSupport, No, PrefixOption, PrefixSupport, TimeoutOption, TimeoutSupport, ToAssign, Yes,
};
use azure::storage::blob::requests::ListBlobBuilder;
use azure::storage::blob::Blob;
use azure::storage::client::Client;
use futures::prelude::*;
use futures::stream;
use std::marker::PhantomData;

#[derive(Debug, Clone)]
pub struct ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    client: &'a Client,
    p_container_name: PhantomData<ContainerNameSet>,
    container_name: Option<&'a str>,
    client_request_id: Option<&'a str>,
    timeout: Option<u64>,
    prefix: Option<&'a str>,
    delimiter: Option<&'a str>,
    include_snapshots: bool,
    include_metadata: bool,
    include_uncommitted_blobs: bool,
    include_copy: bool,
    include_deleted: bool,
}

impl<'a> ListBlobStreamBuilder<'a, No> {
    #[inline]
    pub(crate) fn new(client: &'a Client) -> ListBlobStreamBuilder<'a, No> {
        ListBlobStreamBuilder {
            client,
            p_container_name: PhantomData {},
            container_name: None,
            client_request_id: None,
            timeout: None,
            prefix: None,
            delimiter: None,
            include_snapshots: false,
            include_metadata: false,
            include_uncommitted_blobs: false,
            include_copy: false,
            include_deleted: false,
        }
    }
}

impl<'a, ContainerNameSet> ClientRequired<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn client(&self) -> &'a Client {
        self.client
    }
}

impl<'a> ContainerNameRequired<'a> for ListBlobStreamBuilder<'a, Yes> {
    #[inline]
    fn container_name(&self) -> &'a str {
        self.container_name.unwrap()
    }
}

impl<'a, ContainerNameSet> ClientRequestIdOption<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn client_request_id(&self) -> Option<&'a str> {
        self.client_request_id
    }
}

impl<'a, ContainerNameSet> TimeoutOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn timeout(&self) -> Option<u64> {
        self.timeout
    }
}

impl<'a, ContainerNameSet> PrefixOption<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn prefix(&self) -> Option<&'a str> {
        self.prefix
    }
}

impl<'a, ContainerNameSet> DelimiterOption<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn delimiter(&self) -> Option<&'a str> {
        self.delimiter
    }
}

impl<'a, ContainerNameSet> IncludeSnapshotsOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn include_snapshots(&self) -> bool {
        self.include_snapshots
    }
}

impl<'a, ContainerNameSet> IncludeMetadataOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn include_metadata(&self) -> bool {
        self.include_metadata
    }
}

impl<'a, ContainerNameSet> IncludeUncommittedBlobsOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn include_uncommitted_blobs(&self) -> bool {
        self.include_uncommitted_blobs
    }
}

impl<'a, ContainerNameSet> IncludeCopyOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn include_copy(&self) -> bool {
        self.include_copy
    }
}

impl<'a, ContainerNameSet> IncludeDeletedOption for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    #[inline]
    fn include_deleted(&self) -> bool {
        self.include_deleted
    }
}

impl<'a, ContainerNameSet> ContainerNameSupport<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, Yes>;

    #[inline]
    fn with_container_name(self, container_name: &'a str) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: Some(container_name),
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> ClientRequestIdSupport<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_client_request_id(self, client_request_id: &'a str) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: Some(client_request_id),
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> TimeoutSupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_timeout(self, timeout: u64) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: Some(timeout),
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> PrefixSupport<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_prefix(self, prefix: &'a str) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: Some(prefix),
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> DelimiterSupport<'a> for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_delimiter(self, delimiter: &'a str) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: Some(delimiter),
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> IncludeSnapshotsSupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_include_snapshots(self) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: true,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> IncludeMetadataSupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_include_metadata(self) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: true,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> IncludeUncommittedBlobsSupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_include_uncommitted_blobs(self) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: true,
            include_copy: self.include_copy,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> IncludeCopySupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_include_copy(self) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: true,
            include_deleted: self.include_deleted,
        }
    }
}

impl<'a, ContainerNameSet> IncludeDeletedSupport for ListBlobStreamBuilder<'a, ContainerNameSet>
where
    ContainerNameSet: ToAssign,
{
    type O = ListBlobStreamBuilder<'a, ContainerNameSet>;

    #[inline]
    fn with_include_deleted(self) -> Self::O {
        ListBlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            container_name: self.container_name,
            client_request_id: self.client_request_id,
            timeout: self.timeout,
            prefix: self.prefix,
            delimiter: self.delimiter,
            include_snapshots: self.include_snapshots,
            include_metadata: self.include_metadata,
            include_uncommitted_blobs: self.include_uncommitted_blobs,
            include_copy: self.include_copy,
            include_deleted: true,
        }
    }
}

// methods callable regardless
impl<'a, ContainerNameSet> ListBlobStreamBuilder<'a, ContainerNameSet> where ContainerNameSet: ToAssign {}

// this empty trait is required in order to use IncludeListOptions methods. No duck typing, sorry
// :(
impl<'a> IncludeListOptions for ListBlobStreamBuilder<'a, Yes> {}

enum ContinuationState {
    Start,
    Next(Option<String>),
}

impl<'a> ListBlobStreamBuilder<'a, Yes> {
    #[inline]
    pub fn finalize(self) -> impl Stream<Item = Blob, Error = AzureError> {
        let container_name = self.container_name().to_owned();

        let client_request_id = self.client_request_id.map(|v| v.to_owned());
        let timeout = self.timeout.to_owned();
        let prefix = self.prefix.map(|v| v.to_owned());
        let delimiter = self.delimiter.map(|v| v.to_owned());
        let include_snapshots = self.include_snapshots;
        let include_metadata = self.include_metadata;
        let include_uncommitted_blobs = self.include_uncommitted_blobs;
        let include_copy = self.include_copy;
        let include_deleted = self.include_deleted;

        let client = self.client().clone();

        stream::unfold(ContinuationState::Start, move |cont_token| {
            let marker = match cont_token {
                ContinuationState::Start => None,
                ContinuationState::Next(Some(marker)) => Some(marker),
                ContinuationState::Next(None) => return None,
            };

            let mut req = ListBlobBuilder::new(&client).with_container_name(&container_name);

            if let Some(ref marker) = &marker {
                req = req.with_next_marker(&*marker);
            }
            if let Some(ref client_request_id) = &client_request_id {
                req = req.with_client_request_id(client_request_id);
            }
            if let Some(timeout) = timeout {
                req = req.with_timeout(timeout);
            }
            if let Some(ref prefix) = &prefix {
                req = req.with_prefix(prefix);
            }
            if let Some(ref delimiter) = &delimiter {
                req = req.with_delimiter(delimiter);
            }

            if include_snapshots {
                req = req.with_include_snapshots();
            }
            if include_metadata {
                req = req.with_include_metadata();
            }
            if include_uncommitted_blobs {
                req = req.with_include_uncommitted_blobs();
            }
            if include_copy {
                req = req.with_include_copy();
            }
            if include_deleted {
                req = req.with_include_deleted();
            }

            let req = req.finalize();
            Some(req.map(move |response| {
                let IncompleteVector { token, vector } = response.incomplete_vector;
                (stream::iter_ok(vector), ContinuationState::Next(token))
            }))
        }).flatten()
    }
}
<|endoftext|>


<commit_before>///! File system utilities, particularly functionality that requires
///! alternative implementations for alternative operating systems.
use eyre::{eyre, Result};
use std::{fs, io, os, path::Path};

/// Set permissions on a file
#[allow(unused_variables)]
pub fn set_perms<File: AsRef<Path>>(path: File, mode: u32) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    {
        use os::unix::fs::PermissionsExt;
        fs::set_permissions(path, fs::Permissions::from_mode(mode))?;
    }

    Ok(())
}

/// Create a symbolic (soft) link to a file
pub fn symlink_file<Original: AsRef<Path>, Link: AsRef<Path>>(
    original: Original,
    link: Link,
) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    os::unix::fs::symlink(original, link)?;

    #[cfg(target_os = "windows")]
    os::windows::fs::symlink_file(original, link)?;

    Ok(())
}

/// Create a symbolic (soft) link to a directory
pub fn symlink_dir<Original: AsRef<Path>, Link: AsRef<Path>>(
    original: Original,
    link: Link,
) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    os::unix::fs::symlink(original, link)?;

    #[cfg(target_os = "windows")]
    os::windows::fs::symlink_dir(original, link)?;

    Ok(())
}

/// Clear a directory
pub fn clear_dir_all(dir: impl AsRef<Path>) -> Result<()> {
    fs::remove_dir_all(&dir)?;
    fs::create_dir_all(&dir)?;
    Ok(())
}

/// Recursively copy a directory to another
pub fn copy_dir_all(src: impl AsRef<Path>, dest: impl AsRef<Path>) -> Result<()> {
    fs::create_dir_all(&dest)?;
    for entry in fs::read_dir(src)? {
        let entry = entry?;
        if entry.file_type()?.is_dir() {
            copy_dir_all(entry.path(), dest.as_ref().join(entry.file_name()))?;
        } else if let Err(error) = fs::copy(entry.path(), dest.as_ref().join(entry.file_name())) {
            // Ignore "the source path is neither a regular file nor a symlink to a regular file" errors
            if !matches!(error.kind(), io::ErrorKind::InvalidInput) {
                return Err(eyre!(error));
            }
        }
    }
    Ok(())
}
<commit_msg>feat(Filesystem utils): Add `copy_if_exists` function<commit_after>///! File system utilities, particularly functionality that requires
///! alternative implementations for alternative operating systems.
use eyre::{eyre, Result};
use std::{fs, io, os, path::Path};

/// Set permissions on a file
#[allow(unused_variables)]
pub fn set_perms<File: AsRef<Path>>(path: File, mode: u32) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    {
        use os::unix::fs::PermissionsExt;
        fs::set_permissions(path, fs::Permissions::from_mode(mode))?;
    }

    Ok(())
}

/// Create a symbolic (soft) link to a file
pub fn symlink_file<Original: AsRef<Path>, Link: AsRef<Path>>(
    original: Original,
    link: Link,
) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    os::unix::fs::symlink(original, link)?;

    #[cfg(target_os = "windows")]
    os::windows::fs::symlink_file(original, link)?;

    Ok(())
}

/// Create a symbolic (soft) link to a directory
pub fn symlink_dir<Original: AsRef<Path>, Link: AsRef<Path>>(
    original: Original,
    link: Link,
) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    os::unix::fs::symlink(original, link)?;

    #[cfg(target_os = "windows")]
    os::windows::fs::symlink_dir(original, link)?;

    Ok(())
}

/// Copy a file or directory if it exists
pub fn copy_if_exists(src: impl AsRef<Path>, dest: impl AsRef<Path>) -> Result<()> {
    let src = src.as_ref();
    if src.exists() {
        if src.is_dir() {
            copy_dir_all(src, dest)?;
        } else {
            fs::copy(src, dest)?;
        }
    }
    Ok(())
}

/// Clear a directory
pub fn clear_dir_all(dir: impl AsRef<Path>) -> Result<()> {
    fs::remove_dir_all(&dir)?;
    fs::create_dir_all(&dir)?;
    Ok(())
}

/// Recursively copy a directory to another
pub fn copy_dir_all(src: impl AsRef<Path>, dest: impl AsRef<Path>) -> Result<()> {
    fs::create_dir_all(&dest)?;
    for entry in fs::read_dir(src)? {
        let entry = entry?;
        if entry.file_type()?.is_dir() {
            copy_dir_all(entry.path(), dest.as_ref().join(entry.file_name()))?;
        } else if let Err(error) = fs::copy(entry.path(), dest.as_ref().join(entry.file_name())) {
            // Ignore "the source path is neither a regular file nor a symlink to a regular file" errors
            if !matches!(error.kind(), io::ErrorKind::InvalidInput) {
                return Err(eyre!(error));
            }
        }
    }
    Ok(())
}

/// Move a directory
///
/// This is a lot less efficient than `std::fs::rename` but will work across mounts
pub fn move_dir_all(src: impl AsRef<Path>, dest: impl AsRef<Path>) -> Result<()> {
    copy_dir_all(&src, &dest)?;
    fs::remove_dir_all(&src)?;
    Ok(())
}
<|endoftext|>


<commit_before>pub mod line;

use std::cmp::{max, min};
use std::mem;
use std::str;

use rustbox::{RustBox};

use self::line::Line;
use tui::style::StyleRef;

pub struct MsgArea {
    lines       : Vec<Line>,

    // Rendering related
    width       : i32,
    height      : i32,

    /// Vertical scroll: An offset from the last visible line.
    /// E.g. when this is 0, `self.lines[self.lines.len() - 1]` is drawn at the
    /// bottom of screen.
    scroll      : i32,

    line_buf    : Line,
}

impl MsgArea {
    pub fn new(width : i32, height : i32) -> MsgArea {
        MsgArea {
            lines: Vec::new(),
            width: width,
            height: height,
            scroll: 0,
            line_buf: Line::new(),
        }
    }

    pub fn resize(&mut self, width : i32, height : i32) {
        self.width = width;
        self.height = height;
    }

    pub fn draw(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        let mut row = pos_y + self.height - 1;

        // Draw lines in reverse order
        let mut line_idx = ((self.lines.len() as i32) - 1) - self.scroll;
        while line_idx > 0 && row >= pos_y {
            let line = unsafe { self.lines.get_unchecked(line_idx as usize) };

            // Where to start rendering this line?
            let line_height = line.rendered_height(self.width);
            let line_row = row - line_height + 1;

            // Do we have enough space to render this line?
            if line_row < pos_y {
                break;
            }

            // Render it
            line.draw(rustbox, pos_x, line_row, self.width);

            row = line_row - 1;
            line_idx -= 1;
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
// Scrolling

impl MsgArea {
    pub fn scroll_up(&mut self) {
        if self.scroll < (self.lines.len() as i32) - 1 {
            self.scroll += 1;
        }
    }

    pub fn scroll_down(&mut self) {
        if self.scroll > 0 {
            self.scroll -= 1;
        }
    }

    pub fn page_up(&mut self) {
        self.scroll = max(0, min((self.lines.len() as i32) - 1, self.scroll + 10));
    }

    pub fn page_down(&mut self) {
        self.scroll = max(0, self.scroll - 10);
    }
}

////////////////////////////////////////////////////////////////////////////////
// Adding text

impl MsgArea {
    pub fn add_text(&mut self, str : &str, style : StyleRef) {
        self.line_buf.add_text(str);
    }

    pub fn flush_line(&mut self) {
        self.lines.push(mem::replace(&mut self.line_buf, Line::new()));
    }
}
<commit_msg>off-by-one<commit_after>pub mod line;

use std::cmp::{max, min};
use std::mem;
use std::str;

use rustbox::{RustBox};

use self::line::Line;
use tui::style::StyleRef;

pub struct MsgArea {
    lines       : Vec<Line>,

    // Rendering related
    width       : i32,
    height      : i32,

    /// Vertical scroll: An offset from the last visible line.
    /// E.g. when this is 0, `self.lines[self.lines.len() - 1]` is drawn at the
    /// bottom of screen.
    scroll      : i32,

    line_buf    : Line,
}

impl MsgArea {
    pub fn new(width : i32, height : i32) -> MsgArea {
        MsgArea {
            lines: Vec::new(),
            width: width,
            height: height,
            scroll: 0,
            line_buf: Line::new(),
        }
    }

    pub fn resize(&mut self, width : i32, height : i32) {
        self.width = width;
        self.height = height;
    }

    pub fn draw(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        let mut row = pos_y + self.height - 1;

        // Draw lines in reverse order
        let mut line_idx = ((self.lines.len() as i32) - 1) - self.scroll;
        while line_idx >= 0 && row >= pos_y {
            let line = unsafe { self.lines.get_unchecked(line_idx as usize) };

            // Where to start rendering this line?
            let line_height = line.rendered_height(self.width);
            let line_row = row - line_height + 1;

            // Do we have enough space to render this line?
            if line_row < pos_y {
                break;
            }

            // Render it
            line.draw(rustbox, pos_x, line_row, self.width);

            row = line_row - 1;
            line_idx -= 1;
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
// Scrolling

impl MsgArea {
    pub fn scroll_up(&mut self) {
        if self.scroll < (self.lines.len() as i32) - 1 {
            self.scroll += 1;
        }
    }

    pub fn scroll_down(&mut self) {
        if self.scroll > 0 {
            self.scroll -= 1;
        }
    }

    pub fn page_up(&mut self) {
        self.scroll = max(0, min((self.lines.len() as i32) - 1, self.scroll + 10));
    }

    pub fn page_down(&mut self) {
        self.scroll = max(0, self.scroll - 10);
    }
}

////////////////////////////////////////////////////////////////////////////////
// Adding text

impl MsgArea {
    pub fn add_text(&mut self, str : &str, style : StyleRef) {
        self.line_buf.add_text(str);
    }

    pub fn flush_line(&mut self) {
        self.lines.push(mem::replace(&mut self.line_buf, Line::new()));
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Chirag B Jadwani <chirag.jadwani@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg, ArgMatches};
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Result, Write};
use std::path::Path;
use std::str::FromStr;
use strum_macros::{AsRefStr, EnumString};
use uucore::display::Quotable;

static ABOUT: &str = "Report or omit repeated lines.";
pub mod options {
    pub static ALL_REPEATED: &str = "all-repeated";
    pub static CHECK_CHARS: &str = "check-chars";
    pub static COUNT: &str = "count";
    pub static IGNORE_CASE: &str = "ignore-case";
    pub static REPEATED: &str = "repeated";
    pub static SKIP_FIELDS: &str = "skip-fields";
    pub static SKIP_CHARS: &str = "skip-chars";
    pub static UNIQUE: &str = "unique";
    pub static ZERO_TERMINATED: &str = "zero-terminated";
    pub static GROUP: &str = "group";
}

static ARG_FILES: &str = "files";

#[derive(PartialEq, Clone, Copy, AsRefStr, EnumString)]
#[strum(serialize_all = "snake_case")]
enum Delimiters {
    Append,
    Prepend,
    Separate,
    Both,
    None,
}

struct Uniq {
    repeats_only: bool,
    uniques_only: bool,
    all_repeated: bool,
    delimiters: Delimiters,
    show_counts: bool,
    skip_fields: Option<usize>,
    slice_start: Option<usize>,
    slice_stop: Option<usize>,
    ignore_case: bool,
    zero_terminated: bool,
}

impl Uniq {
    pub fn print_uniq<R: Read, W: Write>(
        &self,
        reader: &mut BufReader<R>,
        writer: &mut BufWriter<W>,
    ) {
        let mut first_line_printed = false;
        let mut group_count = 1;
        let line_terminator = self.get_line_terminator();
        let mut lines = reader.split(line_terminator).map(get_line_string);
        let mut line = match lines.next() {
            Some(l) => l,
            None => return,
        };

        // compare current `line` with consecutive lines (`next_line`) of the input
        // and if needed, print `line` based on the command line options provided
        for next_line in lines {
            if self.cmp_keys(&line, &next_line) {
                if (group_count == 1 && !self.repeats_only)
                    || (group_count > 1 && !self.uniques_only)
                {
                    self.print_line(writer, &line, group_count, first_line_printed);
                    first_line_printed = true;
                }
                line = next_line;
                group_count = 1;
            } else {
                if self.all_repeated {
                    self.print_line(writer, &line, group_count, first_line_printed);
                    first_line_printed = true;
                    line = next_line;
                }
                group_count += 1;
            }
        }
        if (group_count == 1 && !self.repeats_only) || (group_count > 1 && !self.uniques_only) {
            self.print_line(writer, &line, group_count, first_line_printed);
            first_line_printed = true;
        }
        if (self.delimiters == Delimiters::Append || self.delimiters == Delimiters::Both)
            && first_line_printed
        {
            crash_if_err!(1, writer.write_all(&[line_terminator]));
        }
    }

    fn skip_fields<'a>(&self, line: &'a str) -> &'a str {
        if let Some(skip_fields) = self.skip_fields {
            let mut i = 0;
            let mut char_indices = line.char_indices();
            for _ in 0..skip_fields {
                if char_indices.find(|(_, c)| !c.is_whitespace()) == None {
                    return "";
                }
                match char_indices.find(|(_, c)| c.is_whitespace()) {
                    None => return "",

                    Some((next_field_i, _)) => i = next_field_i,
                }
            }
            &line[i..]
        } else {
            line
        }
    }

    fn get_line_terminator(&self) -> u8 {
        if self.zero_terminated {
            0
        } else {
            b'\n'
        }
    }

    fn cmp_keys(&self, first: &str, second: &str) -> bool {
        self.cmp_key(first, |first_iter| {
            self.cmp_key(second, |second_iter| first_iter.ne(second_iter))
        })
    }

    fn cmp_key<F>(&self, line: &str, mut closure: F) -> bool
    where
        F: FnMut(&mut dyn Iterator<Item = char>) -> bool,
    {
        let fields_to_check = self.skip_fields(line);
        let len = fields_to_check.len();
        let slice_start = self.slice_start.unwrap_or(0);
        let slice_stop = self.slice_stop.unwrap_or(len);
        if len > 0 {
            // fast path: avoid doing any work if there is no need to skip or map to lower-case
            if !self.ignore_case && slice_start == 0 && slice_stop == len {
                return closure(&mut fields_to_check.chars());
            }

            // fast path: avoid skipping
            if self.ignore_case && slice_start == 0 && slice_stop == len {
                return closure(&mut fields_to_check.chars().flat_map(|c| c.to_uppercase()));
            }

            // fast path: we can avoid mapping chars to upper-case, if we don't want to ignore the case
            if !self.ignore_case {
                return closure(&mut fields_to_check.chars().skip(slice_start).take(slice_stop));
            }

            closure(
                &mut fields_to_check
                    .chars()
                    .skip(slice_start)
                    .take(slice_stop)
                    .flat_map(|c| c.to_uppercase()),
            )
        } else {
            closure(&mut fields_to_check.chars())
        }
    }

    fn should_print_delimiter(&self, group_count: usize, first_line_printed: bool) -> bool {
        // if no delimiter option is selected then no other checks needed
        self.delimiters != Delimiters::None
            // print delimiter only before the first line of a group, not between lines of a group
            && group_count == 1
            // if at least one line has been output before current group then print delimiter
            && (first_line_printed
                // or if we need to prepend delimiter then print it even at the start of the output
                || self.delimiters == Delimiters::Prepend
                // the 'both' delimit mode should prepend and append delimiters
                || self.delimiters == Delimiters::Both)
    }

    fn print_line<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        line: &str,
        count: usize,
        first_line_printed: bool,
    ) {
        let line_terminator = self.get_line_terminator();

        if self.should_print_delimiter(count, first_line_printed) {
            crash_if_err!(1, writer.write_all(&[line_terminator]));
        }

        crash_if_err!(
            1,
            if self.show_counts {
                writer.write_all(format!("{:7} {}", count, line).as_bytes())
            } else {
                writer.write_all(line.as_bytes())
            }
        );
        crash_if_err!(1, writer.write_all(&[line_terminator]));
    }
}

fn get_line_string(io_line: Result<Vec<u8>>) -> String {
    let line_bytes = crash_if_err!(1, io_line);
    crash_if_err!(1, String::from_utf8(line_bytes))
}

fn opt_parsed<T: FromStr>(opt_name: &str, matches: &ArgMatches) -> Option<T> {
    matches.value_of(opt_name).map(|arg_str| {
        let opt_val: Option<T> = arg_str.parse().ok();
        opt_val.unwrap_or_else(|| {
            crash!(
                1,
                "Invalid argument for {}: {}",
                opt_name,
                arg_str.maybe_quote()
            )
        })
    })
}

fn usage() -> String {
    format!(
        "{0} [OPTION]... [INPUT [OUTPUT]]...",
        uucore::execution_phrase()
    )
}

fn get_long_usage() -> String {
    String::from(
        "Filter adjacent matching lines from INPUT (or standard input),\n\
        writing to OUTPUT (or standard output).
        Note: 'uniq' does not detect repeated lines unless they are adjacent.\n\
        You may want to sort the input first, or use 'sort -u' without 'uniq'.\n",
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = usage();
    let long_usage = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&long_usage[..])
        .get_matches_from(args);

    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let (in_file_name, out_file_name) = match files.len() {
        0 => ("-".to_owned(), "-".to_owned()),
        1 => (files[0].clone(), "-".to_owned()),
        2 => (files[0].clone(), files[1].clone()),
        _ => {
            // Cannot happen as clap will fail earlier
            crash!(1, "Extra operand: {}", files[2]);
        }
    };

    let uniq = Uniq {
        repeats_only: matches.is_present(options::REPEATED)
            || matches.is_present(options::ALL_REPEATED),
        uniques_only: matches.is_present(options::UNIQUE),
        all_repeated: matches.is_present(options::ALL_REPEATED)
            || matches.is_present(options::GROUP),
        delimiters: get_delimiter(&matches),
        show_counts: matches.is_present(options::COUNT),
        skip_fields: opt_parsed(options::SKIP_FIELDS, &matches),
        slice_start: opt_parsed(options::SKIP_CHARS, &matches),
        slice_stop: opt_parsed(options::CHECK_CHARS, &matches),
        ignore_case: matches.is_present(options::IGNORE_CASE),
        zero_terminated: matches.is_present(options::ZERO_TERMINATED),
    };
    uniq.print_uniq(
        &mut open_input_file(in_file_name),
        &mut open_output_file(out_file_name),
    );

    0
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::ALL_REPEATED)
                .short("D")
                .long(options::ALL_REPEATED)
                .possible_values(&[
                    Delimiters::None.as_ref(), Delimiters::Prepend.as_ref(), Delimiters::Separate.as_ref()
                ])
                .help("print all duplicate lines. Delimiting is done with blank lines. [default: none]")
                .value_name("delimit-method")
                .min_values(0)
                .max_values(1),
        )
        .arg(
            Arg::with_name(options::GROUP)
                .long(options::GROUP)
                .possible_values(&[
                    Delimiters::Separate.as_ref(), Delimiters::Prepend.as_ref(),
                    Delimiters::Append.as_ref(), Delimiters::Both.as_ref()
                ])
                .help("show all items, separating groups with an empty line. [default: separate]")
                .value_name("group-method")
                .min_values(0)
                .max_values(1)
                .conflicts_with_all(&[
                    options::REPEATED,
                    options::ALL_REPEATED,
                    options::UNIQUE,
                ]),
        )
        .arg(
            Arg::with_name(options::CHECK_CHARS)
                .short("w")
                .long(options::CHECK_CHARS)
                .help("compare no more than N characters in lines")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::COUNT)
                .short("c")
                .long(options::COUNT)
                .help("prefix lines by the number of occurrences"),
        )
        .arg(
            Arg::with_name(options::IGNORE_CASE)
                .short("i")
                .long(options::IGNORE_CASE)
                .help("ignore differences in case when comparing"),
        )
        .arg(
            Arg::with_name(options::REPEATED)
                .short("d")
                .long(options::REPEATED)
                .help("only print duplicate lines"),
        )
        .arg(
            Arg::with_name(options::SKIP_CHARS)
                .short("s")
                .long(options::SKIP_CHARS)
                .help("avoid comparing the first N characters")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::SKIP_FIELDS)
                .short("f")
                .long(options::SKIP_FIELDS)
                .help("avoid comparing the first N fields")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::UNIQUE)
                .short("u")
                .long(options::UNIQUE)
                .help("only print unique lines"),
        )
        .arg(
            Arg::with_name(options::ZERO_TERMINATED)
                .short("z")
                .long(options::ZERO_TERMINATED)
                .help("end lines with 0 byte, not newline"),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .max_values(2),
        )
}

fn get_delimiter(matches: &ArgMatches) -> Delimiters {
    let value = matches
        .value_of(options::ALL_REPEATED)
        .or_else(|| matches.value_of(options::GROUP));
    if let Some(delimiter_arg) = value {
        crash_if_err!(1, Delimiters::from_str(delimiter_arg))
    } else if matches.is_present(options::GROUP) {
        Delimiters::Separate
    } else {
        Delimiters::None
    }
}

fn open_input_file(in_file_name: String) -> BufReader<Box<dyn Read + 'static>> {
    let in_file = if in_file_name == "-" {
        Box::new(stdin()) as Box<dyn Read>
    } else {
        let path = Path::new(&in_file_name[..]);
        let in_file = File::open(&path);
        let r = crash_if_err!(1, in_file);
        Box::new(r) as Box<dyn Read>
    };
    BufReader::new(in_file)
}

fn open_output_file(out_file_name: String) -> BufWriter<Box<dyn Write + 'static>> {
    let out_file = if out_file_name == "-" {
        Box::new(stdout()) as Box<dyn Write>
    } else {
        let path = Path::new(&out_file_name[..]);
        let in_file = File::create(&path);
        let w = crash_if_err!(1, in_file);
        Box::new(w) as Box<dyn Write>
    };
    BufWriter::new(out_file)
}
<commit_msg>uniq: use UResult in util<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Chirag B Jadwani <chirag.jadwani@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg, ArgMatches};
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Result, Write};
use std::path::Path;
use std::str::FromStr;
use strum_macros::{AsRefStr, EnumString};
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError};

static ABOUT: &str = "Report or omit repeated lines.";
pub mod options {
    pub static ALL_REPEATED: &str = "all-repeated";
    pub static CHECK_CHARS: &str = "check-chars";
    pub static COUNT: &str = "count";
    pub static IGNORE_CASE: &str = "ignore-case";
    pub static REPEATED: &str = "repeated";
    pub static SKIP_FIELDS: &str = "skip-fields";
    pub static SKIP_CHARS: &str = "skip-chars";
    pub static UNIQUE: &str = "unique";
    pub static ZERO_TERMINATED: &str = "zero-terminated";
    pub static GROUP: &str = "group";
}

static ARG_FILES: &str = "files";

#[derive(PartialEq, Clone, Copy, AsRefStr, EnumString)]
#[strum(serialize_all = "snake_case")]
enum Delimiters {
    Append,
    Prepend,
    Separate,
    Both,
    None,
}

struct Uniq {
    repeats_only: bool,
    uniques_only: bool,
    all_repeated: bool,
    delimiters: Delimiters,
    show_counts: bool,
    skip_fields: Option<usize>,
    slice_start: Option<usize>,
    slice_stop: Option<usize>,
    ignore_case: bool,
    zero_terminated: bool,
}

impl Uniq {
    pub fn print_uniq<R: Read, W: Write>(
        &self,
        reader: &mut BufReader<R>,
        writer: &mut BufWriter<W>,
    ) {
        let mut first_line_printed = false;
        let mut group_count = 1;
        let line_terminator = self.get_line_terminator();
        let mut lines = reader.split(line_terminator).map(get_line_string);
        let mut line = match lines.next() {
            Some(l) => l,
            None => return,
        };

        // compare current `line` with consecutive lines (`next_line`) of the input
        // and if needed, print `line` based on the command line options provided
        for next_line in lines {
            if self.cmp_keys(&line, &next_line) {
                if (group_count == 1 && !self.repeats_only)
                    || (group_count > 1 && !self.uniques_only)
                {
                    self.print_line(writer, &line, group_count, first_line_printed);
                    first_line_printed = true;
                }
                line = next_line;
                group_count = 1;
            } else {
                if self.all_repeated {
                    self.print_line(writer, &line, group_count, first_line_printed);
                    first_line_printed = true;
                    line = next_line;
                }
                group_count += 1;
            }
        }
        if (group_count == 1 && !self.repeats_only) || (group_count > 1 && !self.uniques_only) {
            self.print_line(writer, &line, group_count, first_line_printed);
            first_line_printed = true;
        }
        if (self.delimiters == Delimiters::Append || self.delimiters == Delimiters::Both)
            && first_line_printed
        {
            crash_if_err!(1, writer.write_all(&[line_terminator]));
        }
    }

    fn skip_fields<'a>(&self, line: &'a str) -> &'a str {
        if let Some(skip_fields) = self.skip_fields {
            let mut i = 0;
            let mut char_indices = line.char_indices();
            for _ in 0..skip_fields {
                if char_indices.find(|(_, c)| !c.is_whitespace()) == None {
                    return "";
                }
                match char_indices.find(|(_, c)| c.is_whitespace()) {
                    None => return "",

                    Some((next_field_i, _)) => i = next_field_i,
                }
            }
            &line[i..]
        } else {
            line
        }
    }

    fn get_line_terminator(&self) -> u8 {
        if self.zero_terminated {
            0
        } else {
            b'\n'
        }
    }

    fn cmp_keys(&self, first: &str, second: &str) -> bool {
        self.cmp_key(first, |first_iter| {
            self.cmp_key(second, |second_iter| first_iter.ne(second_iter))
        })
    }

    fn cmp_key<F>(&self, line: &str, mut closure: F) -> bool
    where
        F: FnMut(&mut dyn Iterator<Item = char>) -> bool,
    {
        let fields_to_check = self.skip_fields(line);
        let len = fields_to_check.len();
        let slice_start = self.slice_start.unwrap_or(0);
        let slice_stop = self.slice_stop.unwrap_or(len);
        if len > 0 {
            // fast path: avoid doing any work if there is no need to skip or map to lower-case
            if !self.ignore_case && slice_start == 0 && slice_stop == len {
                return closure(&mut fields_to_check.chars());
            }

            // fast path: avoid skipping
            if self.ignore_case && slice_start == 0 && slice_stop == len {
                return closure(&mut fields_to_check.chars().flat_map(|c| c.to_uppercase()));
            }

            // fast path: we can avoid mapping chars to upper-case, if we don't want to ignore the case
            if !self.ignore_case {
                return closure(&mut fields_to_check.chars().skip(slice_start).take(slice_stop));
            }

            closure(
                &mut fields_to_check
                    .chars()
                    .skip(slice_start)
                    .take(slice_stop)
                    .flat_map(|c| c.to_uppercase()),
            )
        } else {
            closure(&mut fields_to_check.chars())
        }
    }

    fn should_print_delimiter(&self, group_count: usize, first_line_printed: bool) -> bool {
        // if no delimiter option is selected then no other checks needed
        self.delimiters != Delimiters::None
            // print delimiter only before the first line of a group, not between lines of a group
            && group_count == 1
            // if at least one line has been output before current group then print delimiter
            && (first_line_printed
                // or if we need to prepend delimiter then print it even at the start of the output
                || self.delimiters == Delimiters::Prepend
                // the 'both' delimit mode should prepend and append delimiters
                || self.delimiters == Delimiters::Both)
    }

    fn print_line<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        line: &str,
        count: usize,
        first_line_printed: bool,
    ) {
        let line_terminator = self.get_line_terminator();

        if self.should_print_delimiter(count, first_line_printed) {
            crash_if_err!(1, writer.write_all(&[line_terminator]));
        }

        crash_if_err!(
            1,
            if self.show_counts {
                writer.write_all(format!("{:7} {}", count, line).as_bytes())
            } else {
                writer.write_all(line.as_bytes())
            }
        );
        crash_if_err!(1, writer.write_all(&[line_terminator]));
    }
}

fn get_line_string(io_line: Result<Vec<u8>>) -> String {
    let line_bytes = crash_if_err!(1, io_line);
    crash_if_err!(1, String::from_utf8(line_bytes))
}

fn opt_parsed<T: FromStr>(opt_name: &str, matches: &ArgMatches) -> Option<T> {
    matches.value_of(opt_name).map(|arg_str| {
        let opt_val: Option<T> = arg_str.parse().ok();
        opt_val.unwrap_or_else(|| {
            crash!(
                1,
                "Invalid argument for {}: {}",
                opt_name,
                arg_str.maybe_quote()
            )
        })
    })
}

fn usage() -> String {
    format!(
        "{0} [OPTION]... [INPUT [OUTPUT]]...",
        uucore::execution_phrase()
    )
}

fn get_long_usage() -> String {
    String::from(
        "Filter adjacent matching lines from INPUT (or standard input),\n\
        writing to OUTPUT (or standard output).
        Note: 'uniq' does not detect repeated lines unless they are adjacent.\n\
        You may want to sort the input first, or use 'sort -u' without 'uniq'.\n",
    )
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let usage = usage();
    let long_usage = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&long_usage[..])
        .get_matches_from(args);

    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let (in_file_name, out_file_name) = match files.len() {
        0 => ("-".to_owned(), "-".to_owned()),
        1 => (files[0].clone(), "-".to_owned()),
        2 => (files[0].clone(), files[1].clone()),
        _ => {
            // Cannot happen as clap will fail earlier
            return Err(USimpleError::new(1, format!("Extra operand: {}", files[2])));
        }
    };

    let uniq = Uniq {
        repeats_only: matches.is_present(options::REPEATED)
            || matches.is_present(options::ALL_REPEATED),
        uniques_only: matches.is_present(options::UNIQUE),
        all_repeated: matches.is_present(options::ALL_REPEATED)
            || matches.is_present(options::GROUP),
        delimiters: get_delimiter(&matches),
        show_counts: matches.is_present(options::COUNT),
        skip_fields: opt_parsed(options::SKIP_FIELDS, &matches),
        slice_start: opt_parsed(options::SKIP_CHARS, &matches),
        slice_stop: opt_parsed(options::CHECK_CHARS, &matches),
        ignore_case: matches.is_present(options::IGNORE_CASE),
        zero_terminated: matches.is_present(options::ZERO_TERMINATED),
    };
    uniq.print_uniq(
        &mut open_input_file(in_file_name),
        &mut open_output_file(out_file_name),
    );

    Ok(())
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::ALL_REPEATED)
                .short("D")
                .long(options::ALL_REPEATED)
                .possible_values(&[
                    Delimiters::None.as_ref(), Delimiters::Prepend.as_ref(), Delimiters::Separate.as_ref()
                ])
                .help("print all duplicate lines. Delimiting is done with blank lines. [default: none]")
                .value_name("delimit-method")
                .min_values(0)
                .max_values(1),
        )
        .arg(
            Arg::with_name(options::GROUP)
                .long(options::GROUP)
                .possible_values(&[
                    Delimiters::Separate.as_ref(), Delimiters::Prepend.as_ref(),
                    Delimiters::Append.as_ref(), Delimiters::Both.as_ref()
                ])
                .help("show all items, separating groups with an empty line. [default: separate]")
                .value_name("group-method")
                .min_values(0)
                .max_values(1)
                .conflicts_with_all(&[
                    options::REPEATED,
                    options::ALL_REPEATED,
                    options::UNIQUE,
                ]),
        )
        .arg(
            Arg::with_name(options::CHECK_CHARS)
                .short("w")
                .long(options::CHECK_CHARS)
                .help("compare no more than N characters in lines")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::COUNT)
                .short("c")
                .long(options::COUNT)
                .help("prefix lines by the number of occurrences"),
        )
        .arg(
            Arg::with_name(options::IGNORE_CASE)
                .short("i")
                .long(options::IGNORE_CASE)
                .help("ignore differences in case when comparing"),
        )
        .arg(
            Arg::with_name(options::REPEATED)
                .short("d")
                .long(options::REPEATED)
                .help("only print duplicate lines"),
        )
        .arg(
            Arg::with_name(options::SKIP_CHARS)
                .short("s")
                .long(options::SKIP_CHARS)
                .help("avoid comparing the first N characters")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::SKIP_FIELDS)
                .short("f")
                .long(options::SKIP_FIELDS)
                .help("avoid comparing the first N fields")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::UNIQUE)
                .short("u")
                .long(options::UNIQUE)
                .help("only print unique lines"),
        )
        .arg(
            Arg::with_name(options::ZERO_TERMINATED)
                .short("z")
                .long(options::ZERO_TERMINATED)
                .help("end lines with 0 byte, not newline"),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .max_values(2),
        )
}

fn get_delimiter(matches: &ArgMatches) -> Delimiters {
    let value = matches
        .value_of(options::ALL_REPEATED)
        .or_else(|| matches.value_of(options::GROUP));
    if let Some(delimiter_arg) = value {
        crash_if_err!(1, Delimiters::from_str(delimiter_arg))
    } else if matches.is_present(options::GROUP) {
        Delimiters::Separate
    } else {
        Delimiters::None
    }
}

fn open_input_file(in_file_name: String) -> BufReader<Box<dyn Read + 'static>> {
    let in_file = if in_file_name == "-" {
        Box::new(stdin()) as Box<dyn Read>
    } else {
        let path = Path::new(&in_file_name[..]);
        let in_file = File::open(&path);
        let r = crash_if_err!(1, in_file);
        Box::new(r) as Box<dyn Read>
    };
    BufReader::new(in_file)
}

fn open_output_file(out_file_name: String) -> BufWriter<Box<dyn Write + 'static>> {
    let out_file = if out_file_name == "-" {
        Box::new(stdout()) as Box<dyn Write>
    } else {
        let path = Path::new(&out_file_name[..]);
        let in_file = File::create(&path);
        let w = crash_if_err!(1, in_file);
        Box::new(w) as Box<dyn Write>
    };
    BufWriter::new(out_file)
}
<|endoftext|>


<commit_before>extern crate gannai;
extern crate argparse;
extern crate rand;
extern crate rustc_serialize;

use rustc_serialize::json;

use gannai::neural_network::{ApplyConf, Network};
use gannai::tools::common::{make_conf, make_network_buf};

struct Args {
    conf: String,
    network: String,
}

fn main() {
    let mut args = Args {conf: String::new(), network: String::new()};
    parse_args(&mut args);
    let conf = make_conf::<ApplyConf>(&args.conf);
    let network_buf = make_network_buf(&args.network);
    apply(&conf, &network_buf.as_network());
}

fn parse_args(args: &mut Args) {
    use argparse::{ArgumentParser, Store};
    let mut parser = ArgumentParser::new();
    parser.set_description("Applies neural network to input data");
    parser.refer(&mut args.conf)
        .add_argument("conf", Store, "Path to conf json file").required();
    parser.refer(&mut args.network)
        .add_argument("network", Store, "Path to neural network json file").required();
    parser.parse_args_or_exit();
}

fn apply(conf: &ApplyConf, network: &Network) {
    use std::io::{BufRead, stdin};
    use gannai::neural_network::Apply;
    let application = network.apply(&conf);
    let file = stdin();
    for line in file.lock().lines() {
        let data = line.unwrap();
        let input: Input = json::decode(&data).unwrap();
        let output_values = application.perform(&input.input[..]);
        let output = Output {input: input.input, output: output_values};
        println!("{}", json::encode(&output).unwrap());
    }
}

#[derive(RustcDecodable)]
struct Input {
    input: Vec<f64>,
}

#[derive(RustcEncodable)]
struct Output {
    input: Vec<f64>,
    output: Vec<f64>,
}
<commit_msg>Use output values in apply tool<commit_after>extern crate gannai;
extern crate argparse;
extern crate rand;
extern crate rustc_serialize;

use rustc_serialize::json;

use gannai::neural_network::{ApplyConf, Network};
use gannai::tools::common::{make_conf, make_network_buf};

struct Args {
    conf: String,
    network: String,
}

fn main() {
    let mut args = Args {conf: String::new(), network: String::new()};
    parse_args(&mut args);
    let conf = make_conf::<ApplyConf>(&args.conf);
    let network_buf = make_network_buf(&args.network);
    apply(&conf, &network_buf.as_network());
}

fn parse_args(args: &mut Args) {
    use argparse::{ArgumentParser, Store};
    let mut parser = ArgumentParser::new();
    parser.set_description("Applies neural network to input data");
    parser.refer(&mut args.conf)
        .add_argument("conf", Store, "Path to conf json file").required();
    parser.refer(&mut args.network)
        .add_argument("network", Store, "Path to neural network json file").required();
    parser.parse_args_or_exit();
}

fn apply(conf: &ApplyConf, network: &Network) {
    use std::io::{BufRead, stdin};
    use gannai::neural_network::Apply;
    let application = network.apply(&conf);
    let file = stdin();
    for line in file.lock().lines() {
        let data = line.unwrap();
        let input: Input = json::decode(&data).unwrap();
        let result_values = application.perform(&input.input[..]);
        let output = Output {input: input.input, output: input.output, result: result_values};
        println!("{}", json::encode(&output).unwrap());
    }
}

#[derive(RustcDecodable)]
struct Input {
    input: Vec<f64>,
    output: Option<Vec<f64>>,
}

#[derive(RustcEncodable)]
struct Output {
    input: Vec<f64>,
    output: Option<Vec<f64>>,
    result: Vec<f64>,
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Tidy check to ensure `#[test]` is not used directly inside `libcore`.
//!
//! `#![no_core]` libraries cannot be tested directly due to duplicating lang
//! item. All tests must be written externally in `libcore/tests`.

use std::path::Path;
use std::fs::read_to_string;

pub fn check(path: &Path, bad: &mut bool) {
    let libcore_path = path.join("libcore");
    super::walk(
        &libcore_path,
        &mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"),
        &mut |subpath| {
            if subpath.ends_with(".rs") {
                if t!(read_to_string(subpath)).contains("#[test]") {
                    tidy_error!(
                        bad,
                        "{} contains #[test]; libcore tests must be placed inside \
                        `src/libcore/tests/`",
                        subpath.display()
                    );
                }
            }
        },
    );
}
<commit_msg>Display the name of the failed file in tidy/libcoretest<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Tidy check to ensure `#[test]` is not used directly inside `libcore`.
//!
//! `#![no_core]` libraries cannot be tested directly due to duplicating lang
//! item. All tests must be written externally in `libcore/tests`.

use std::path::Path;
use std::fs::read_to_string;

pub fn check(path: &Path, bad: &mut bool) {
    let libcore_path = path.join("libcore");
    super::walk(
        &libcore_path,
        &mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"),
        &mut |subpath| {
            if let Some("rs") = subpath.extension().and_then(|e| e.to_str()) {
                match read_to_string(subpath) {
                    Ok(contents) => {
                        if contents.contains("#[test]") {
                            tidy_error!(
                                bad,
                                "{} contains #[test]; libcore tests must be placed inside \
                                `src/libcore/tests/`",
                                subpath.display()
                            );
                        }
                    }
                    Err(err) => {
                        panic!("failed to read file {:?}: {}", subpath, err);
                    }
                }
            }
        },
    );
}
<|endoftext|>


<commit_before>use std::cmp::{max, min};

use unicode_width::UnicodeWidthStr;

use crate::buffer::Buffer;
use crate::layout::Rect;
use crate::style::Style;
use crate::symbols::bar;
use crate::widgets::{Block, Widget};

/// Display multiple bars in a single widgets
///
/// # Examples
///
/// ```
/// # use tui::widgets::{Block, Borders, BarChart};
/// # use tui::style::{Style, Color, Modifier};
/// # fn main() {
/// BarChart::default()
///     .block(Block::default().title("BarChart").borders(Borders::ALL))
///     .bar_width(3)
///     .bar_gap(1)
///     .style(Style::default().fg(Color::Yellow).bg(Color::Red))
///     .value_style(Style::default().fg(Color::Red).modifier(Modifier::BOLD))
///     .label_style(Style::default().fg(Color::White))
///     .data(&[("B0", 0), ("B1", 2), ("B2", 4), ("B3", 3)])
///     .max(4);
/// # }
/// ```
pub struct BarChart<'a> {
    /// Block to wrap the widget in
    block: Option<Block<'a>>,
    /// The width of each bar
    bar_width: u16,
    /// The gap between each bar
    bar_gap: u16,
    /// Style of the values printed at the bottom of each bar
    value_style: Style,
    /// Style of the labels printed under each bar
    label_style: Style,
    /// Style for the widget
    style: Style,
    /// Slice of (label, value) pair to plot on the chart
    data: &'a [(&'a str, u64)],
    /// Value necessary for a bar to reach the maximum height (if no value is specified,
    /// the maximum value in the data is taken as reference)
    max: Option<u64>,
    /// Values to display on the bar (computed when the data is passed to the widget)
    values: Vec<String>,
}

impl<'a> Default for BarChart<'a> {
    fn default() -> BarChart<'a> {
        BarChart {
            block: None,
            max: None,
            data: &[],
            values: Vec::new(),
            bar_width: 1,
            bar_gap: 1,
            value_style: Default::default(),
            label_style: Default::default(),
            style: Default::default(),
        }
    }
}

impl<'a> BarChart<'a> {
    pub fn data(mut self, data: &'a [(&'a str, u64)]) -> BarChart<'a> {
        self.data = data;
        self.values = Vec::with_capacity(self.data.len());
        for &(_, v) in self.data {
            self.values.push(format!("{}", v));
        }
        self
    }

    pub fn block(mut self, block: Block<'a>) -> BarChart<'a> {
        self.block = Some(block);
        self
    }
    pub fn max(mut self, max: u64) -> BarChart<'a> {
        self.max = Some(max);
        self
    }

    pub fn bar_width(mut self, width: u16) -> BarChart<'a> {
        self.bar_width = width;
        self
    }
    pub fn bar_gap(mut self, gap: u16) -> BarChart<'a> {
        self.bar_gap = gap;
        self
    }
    pub fn value_style(mut self, style: Style) -> BarChart<'a> {
        self.value_style = style;
        self
    }
    pub fn label_style(mut self, style: Style) -> BarChart<'a> {
        self.label_style = style;
        self
    }
    pub fn style(mut self, style: Style) -> BarChart<'a> {
        self.style = style;
        self
    }
}

impl<'a> Widget for BarChart<'a> {
    fn draw(&mut self, area: Rect, buf: &mut Buffer) {
        let chart_area = match self.block {
            Some(ref mut b) => {
                b.draw(area, buf);
                b.inner(area)
            }
            None => area,
        };

        if chart_area.height < 2 {
            return;
        }

        self.background(chart_area, buf, self.style.bg);

        let max = self
            .max
            .unwrap_or_else(|| self.data.iter().fold(0, |acc, &(_, v)| max(v, acc)));
        let max_index = min(
            (chart_area.width / (self.bar_width + self.bar_gap)) as usize,
            self.data.len(),
        );
        let mut data = self
            .data
            .iter()
            .take(max_index)
            .map(|&(l, v)| (l, v * u64::from(chart_area.height) * 8 / max))
            .collect::<Vec<(&str, u64)>>();
        for j in (0..chart_area.height - 1).rev() {
            for (i, d) in data.iter_mut().enumerate() {
                let symbol = match d.1 {
                    0 => " ",
                    1 => bar::ONE_EIGHTH,
                    2 => bar::ONE_QUATER,
                    3 => bar::THREE_EIGHTHS,
                    4 => bar::HALF,
                    5 => bar::FIVE_EIGHTHS,
                    6 => bar::THREE_QUATERS,
                    7 => bar::SEVEN_EIGHTHS,
                    _ => bar::FULL,
                };

                for x in 0..self.bar_width {
                    buf.get_mut(
                        chart_area.left() + i as u16 * (self.bar_width + self.bar_gap) + x,
                        chart_area.top() + j,
                    )
                    .set_symbol(symbol)
                    .set_style(self.style);
                }

                if d.1 > 8 {
                    d.1 -= 8;
                } else {
                    d.1 = 0;
                }
            }
        }

        for (i, &(label, value)) in self.data.iter().take(max_index).enumerate() {
            if value != 0 {
                let value_label = &self.values[i];
                let width = value_label.width() as u16;
                if width < self.bar_width {
                    buf.set_string(
                        chart_area.left()
                            + i as u16 * (self.bar_width + self.bar_gap)
                            + (self.bar_width - width) / 2,
                        chart_area.bottom() - 2,
                        value_label,
                        self.value_style,
                    );
                }
            }
            buf.set_stringn(
                chart_area.left() + i as u16 * (self.bar_width + self.bar_gap),
                chart_area.bottom() - 1,
                label,
                self.bar_width as usize,
                self.label_style,
            );
        }
    }
}
<commit_msg>avoid divide by zero<commit_after>use std::cmp::{max, min};

use unicode_width::UnicodeWidthStr;

use crate::buffer::Buffer;
use crate::layout::Rect;
use crate::style::Style;
use crate::symbols::bar;
use crate::widgets::{Block, Widget};

/// Display multiple bars in a single widgets
///
/// # Examples
///
/// ```
/// # use tui::widgets::{Block, Borders, BarChart};
/// # use tui::style::{Style, Color, Modifier};
/// # fn main() {
/// BarChart::default()
///     .block(Block::default().title("BarChart").borders(Borders::ALL))
///     .bar_width(3)
///     .bar_gap(1)
///     .style(Style::default().fg(Color::Yellow).bg(Color::Red))
///     .value_style(Style::default().fg(Color::Red).modifier(Modifier::BOLD))
///     .label_style(Style::default().fg(Color::White))
///     .data(&[("B0", 0), ("B1", 2), ("B2", 4), ("B3", 3)])
///     .max(4);
/// # }
/// ```
pub struct BarChart<'a> {
    /// Block to wrap the widget in
    block: Option<Block<'a>>,
    /// The width of each bar
    bar_width: u16,
    /// The gap between each bar
    bar_gap: u16,
    /// Style of the values printed at the bottom of each bar
    value_style: Style,
    /// Style of the labels printed under each bar
    label_style: Style,
    /// Style for the widget
    style: Style,
    /// Slice of (label, value) pair to plot on the chart
    data: &'a [(&'a str, u64)],
    /// Value necessary for a bar to reach the maximum height (if no value is specified,
    /// the maximum value in the data is taken as reference)
    max: Option<u64>,
    /// Values to display on the bar (computed when the data is passed to the widget)
    values: Vec<String>,
}

impl<'a> Default for BarChart<'a> {
    fn default() -> BarChart<'a> {
        BarChart {
            block: None,
            max: None,
            data: &[],
            values: Vec::new(),
            bar_width: 1,
            bar_gap: 1,
            value_style: Default::default(),
            label_style: Default::default(),
            style: Default::default(),
        }
    }
}

impl<'a> BarChart<'a> {
    pub fn data(mut self, data: &'a [(&'a str, u64)]) -> BarChart<'a> {
        self.data = data;
        self.values = Vec::with_capacity(self.data.len());
        for &(_, v) in self.data {
            self.values.push(format!("{}", v));
        }
        self
    }

    pub fn block(mut self, block: Block<'a>) -> BarChart<'a> {
        self.block = Some(block);
        self
    }
    pub fn max(mut self, max: u64) -> BarChart<'a> {
        self.max = Some(max);
        self
    }

    pub fn bar_width(mut self, width: u16) -> BarChart<'a> {
        self.bar_width = width;
        self
    }
    pub fn bar_gap(mut self, gap: u16) -> BarChart<'a> {
        self.bar_gap = gap;
        self
    }
    pub fn value_style(mut self, style: Style) -> BarChart<'a> {
        self.value_style = style;
        self
    }
    pub fn label_style(mut self, style: Style) -> BarChart<'a> {
        self.label_style = style;
        self
    }
    pub fn style(mut self, style: Style) -> BarChart<'a> {
        self.style = style;
        self
    }
}

impl<'a> Widget for BarChart<'a> {
    fn draw(&mut self, area: Rect, buf: &mut Buffer) {
        let chart_area = match self.block {
            Some(ref mut b) => {
                b.draw(area, buf);
                b.inner(area)
            }
            None => area,
        };

        if chart_area.height < 2 {
            return;
        }

        self.background(chart_area, buf, self.style.bg);

        let max = self
            .max
            .unwrap_or_else(|| self.data.iter().fold(0, |acc, &(_, v)| max(v, acc)));
        let max_index = min(
            (chart_area.width / (self.bar_width + self.bar_gap)) as usize,
            self.data.len(),
        );
        let mut data = self
            .data
            .iter()
            .take(max_index)
            .map(|&(l, v)| (l, v * u64::from(chart_area.height) * 8 / std::cmp::max(max, 1)))
            .collect::<Vec<(&str, u64)>>();
        for j in (0..chart_area.height - 1).rev() {
            for (i, d) in data.iter_mut().enumerate() {
                let symbol = match d.1 {
                    0 => " ",
                    1 => bar::ONE_EIGHTH,
                    2 => bar::ONE_QUATER,
                    3 => bar::THREE_EIGHTHS,
                    4 => bar::HALF,
                    5 => bar::FIVE_EIGHTHS,
                    6 => bar::THREE_QUATERS,
                    7 => bar::SEVEN_EIGHTHS,
                    _ => bar::FULL,
                };

                for x in 0..self.bar_width {
                    buf.get_mut(
                        chart_area.left() + i as u16 * (self.bar_width + self.bar_gap) + x,
                        chart_area.top() + j,
                    )
                    .set_symbol(symbol)
                    .set_style(self.style);
                }

                if d.1 > 8 {
                    d.1 -= 8;
                } else {
                    d.1 = 0;
                }
            }
        }

        for (i, &(label, value)) in self.data.iter().take(max_index).enumerate() {
            if value != 0 {
                let value_label = &self.values[i];
                let width = value_label.width() as u16;
                if width < self.bar_width {
                    buf.set_string(
                        chart_area.left()
                            + i as u16 * (self.bar_width + self.bar_gap)
                            + (self.bar_width - width) / 2,
                        chart_area.bottom() - 2,
                        value_label,
                        self.value_style,
                    );
                }
            }
            buf.set_stringn(
                chart_area.left() + i as u16 * (self.bar_width + self.bar_gap),
                chart_area.bottom() - 1,
                label,
                self.bar_width as usize,
                self.label_style,
            );
        }
    }
}
<|endoftext|>