// Copyright 2017 The Mellium Authors. All rights reserved.
//
// 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.

//! A simple interface with methods for manipulating sets.
//!
//! # Examples
//!
//! ```rust
//! use set;
//! use set::Set;
//!
//! // A set that contains ASCII
//! let ascii = set::predicate(|c| c as u32 <= 0x7F);
//! assert!(ascii.contains('a'));
//! assert!(!ascii.contains('❤'));
//!
//! let s = set::predicate(|c: char| c.is_uppercase());
//! assert!(s.contains('B'));
//!
//! // A char is a quine atom. That is, it is a set that contains only itself.
//! assert!('t'.contains('t'));
//!
//! // Functions and closures that match the signature of contains are themselves sets.
//! assert!(char::is_lowercase.contains('b'));
//! ```

#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/set/0.1.1")]

#![cfg_attr(feature = "no_std", no_std)]

#[cfg(not(feature = "no_std"))]
use std::marker;

#[cfg(feature = "no_std")]
use core::marker;

/// A simple trait representing a set.
///
/// See the crate docs for usage examples.
pub trait Set<T> {
    /// Checks if the item is contained in the set.
    fn contains(&self, c: T) -> bool;
}

impl Set<char> for char {
    fn contains(&self, c: char) -> bool {
        *self == c
    }
}

impl<T, F: Fn(T) -> bool> Set<T> for F {
    fn contains(&self, c: T) -> bool {
        (self)(c)
    }
}

/// Returns a set with a contains method that calls f(c).
///
/// # Examples
///
/// ```rust
/// use set;
/// use set::Set;
///
/// // A set that contains only the char 'a'
/// let s = set::predicate(|c| c == 'a');
///
/// assert!(s.contains('a'));
/// assert!(!s.contains('b'));
/// ```
pub fn predicate<T, F: Set<T>>(f: F) -> PredicateSet<T, F> {
    PredicateSet {
        f: f,
        phantom: marker::PhantomData,
    }
}

/// Implements Set using a predicate callable. Normally created via the [`predicate`] function.
///
/// [`predicate`]: fn.predicate.html
pub struct PredicateSet<T, F: Set<T>> {
    f: F,
    phantom: marker::PhantomData<T>,
}

impl<T, F: Fn(T) -> bool> Set<T> for PredicateSet<T, F> {
    fn contains(&self, c: T) -> bool {
        (self.f)(c)
    }
}
