map_split 0.2.0

A library providing simultaneous mutable access to disjoint portions values stored in a hash map.
Documentation
use std::env;
use std::fs::File;
use std::io::{Write,Result};
use std::path::Path;

const MAX_TYPES: u8 = 26;


pub fn build_trait(out_dir: &String) -> Result<()> {
    let dest_path = Path::new(out_dir).join("splittable.rs");
    let mut f = File::create(&dest_path).unwrap();

    let mut nm1: String = "".to_string();
    for i in 3..(MAX_TYPES+1) {
        try!(write!(f, "
/// A type which can be split into disjoint references. SplitType allows a type to be split multiple
// ways.
pub trait Splittable{n}<'a, SplitType = ()> {{\n", n=i));
        for j in 0..i {
            try!(write!(f, "\ttype {A}: 'a;\n", A=('A' as u8 + j) as char));
        }
        try!(write!(f, "
    fn split{n}(&'a self) -> (", n=i));
        for j in 0..i {
            try!(write!(f, "&'a Self::{A}, ", A=('A' as u8 + j) as char));
        }
        try!(write!(f, ");
    fn split{n}_mut(&'a mut self) -> (", n=i));
        for j in 0..i {
            try!(write!(f, "&'a mut Self::{A}, ", A=('A' as u8 + j) as char));
        }
        try!(write!(f, ");\n}}\n"));

        try!(write!(f, "impl <'a, SplitType, T: Splittable{n}<'a, SplitType>> Splittable{nm1}<'a, SplitType> for T {{\n", nm1=nm1, n=i));
        for j in 0..i-1 {
            try!(write!(f, "\ttype {A} = <Self as Splittable{n}<'a, SplitType>>::{A};\n", A=('A' as u8 + j) as char, n=i));
        }
        try!(write!(f, "\n\tfn split{nm1}(&'a self) -> (", nm1=nm1));
        for j in 0..i-1 {
            try!(write!(f, "&'a Self::{A}, ", A=('A' as u8 + j) as char));
        }
        try!(write!(f, ") {{
        let r = self.split{n}();
        (", n=i));
        for j in 0..i-1 {
            try!(write!(f, "r.{j}, ", j=j));
        }
            try!(write!(f, ")
    }}
    fn split{nm1}_mut(&'a mut self) -> (", nm1=nm1));
        for j in 0..i-1 {
            try!(write!(f, "&'a mut Self::{A}, ", A=('A' as u8 + j) as char));
        }
        try!(write!(f, ") {{
        let r = self.split{n}_mut();
        (", n=i));
        for j in 0..i-1 {
            try!(write!(f, "r.{j}, ", j=j));
        }
        try!(write!(f, ")\n\t}}\n}}\n"));
        nm1 = i.to_string();
    }

    write!(f, "\n")
}

pub fn build_helpers(out_dir: &String) -> Result<()> {
    let dest_path = Path::new(out_dir).join("helpers.rs");
    let mut f = File::create(&dest_path).unwrap();

    for i in 3..(MAX_TYPES+1) {
        try!(write!(f, "
fn iter_{a}_helper<'a, K: 'a, V: 'a, SplitType>((k, v): (&'a K, &'a V)) ->
    (&'a K, &'a <V as Splittable{n}<'a, SplitType>>::{A})
where V: Splittable{n}<'a, SplitType> {{
    (k, v.split{n}().{nm1})
}}

fn iter_mut_{a}_helper<'a, K: 'a, V: 'a, SplitType>((k, v): (&'a K, &'a mut V)) -> (&'a K, &'a mut <V as Splittable{n}<'a, SplitType>>::{A})
where V: Splittable{n}<'a, SplitType> {{
    (k, v.split{n}_mut().{nm1})
}}
\n", n=i, nm1=i-1, A=('A' as u8 + i - 1) as char, a=('a' as u8 + i - 1) as char));

    }

    write!(f, "\n")
}

pub fn build_structs(out_dir: &String) -> Result<()> {
    let dest_path = Path::new(out_dir).join("structs.rs");
    let mut f = File::create(&dest_path).unwrap();

    for i in 3..(MAX_TYPES+1) {
        try!(write!(f, "
/// A wrapper around a HashMap which provides access to the {A} portion of a `Splittable{n}` value type
pub struct HashMap{A}<'a, K: 'a, V: 'a, S: 'a, SplitType>(PhantomData<SplitType>, &'a mut HashMap<K, V, S>)
where K: Eq + Hash, S: BuildHasher;
\n", n=i, A=('A' as u8 + i - 1) as char));
    }

    write!(f, "\n")
}

pub fn build_impls(out_dir: &String) -> Result<()> {
    let dest_path = Path::new(out_dir).join("impls.rs");
    let mut f = File::create(&dest_path).unwrap();

    for i in 3..(MAX_TYPES+1) {
        try!(write!(f, "
impl <'a, K: 'a, V: 'a, S, SplitType> HashMap{A}<'a, K, V, S, SplitType>
where K: Eq + Hash, S: BuildHasher {{
    /// An iterator visiting all key-value pairs in arbitrary order. Iterator element type is
    /// `(&'b K, &'b V::{A})`.
    pub fn iter<'b>(&'b self) -> iter::Map<
        Iter<'b, K, V>,
        fn((&'b K, &'b V)) -> (&'b K, &'b <V as Splittable{n}<'b, SplitType>>::{A}),
    >
    where V: Splittable{n}<'b, SplitType> {{
        self.1.iter().map(iter_{a}_helper::<'b, K, V, SplitType>)
    }}

    /// An iterator visiting all key-value pairs in arbitrary order. Iterator element type is
    /// `(&'b K, &'b mut V::{A})`.
    pub fn iter_mut<'b>(&'b mut self) -> iter::Map<
        IterMut<'b, K, V>,
        fn((&'b K, &'b mut V)) -> (&'b K, &'b mut <V as Splittable{n}<'b, SplitType>>::{A}),
    >
    where V: Splittable{n}<'b, SplitType> {{
        self.1.iter_mut().map(iter_mut_{a}_helper::<'b, K, V, SplitType>)
    }}

    /// Returns the number of elements the map can hold without reallocating.
    ///
    /// This number is a lower bound; the HashMap<K, V> might be able to hold more, but is
    /// guaranteed to be able to hold at least this many.
    pub fn capacity(&self) -> usize {{ self.1.capacity() }}

    /// Returns the number of elements in the map.
    pub fn len(&self) -> usize {{ self.1.len() }}

    /// Returns true if the map contains no elements.
    pub fn is_empty(&self) -> bool {{ self.1.is_empty() }}

    /// Returns a reference to the value corresponding to the key.
    ///
    /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed
    /// form must match those for the key type.
    pub fn get<'b, Q: ?Sized>(&'b self, k: &Q) -> Option<&'b <V as Splittable{n}<'b, SplitType>>::{A}>
    where Q: Hash + Eq, K: Borrow<Q>, V: Splittable{n}<'b, SplitType> {{
        self.1.get(k).map(|v| v.split{n}().{nm1})
    }}

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed
    /// form must match those for the key type.
    pub fn get_mut<'b, Q: ?Sized>(&'b mut self, k: &Q) -> Option<&'b mut <V as Splittable{n}<'b, SplitType>>::{A}>
    where Q: Hash + Eq, K: Borrow<Q>, V: Splittable{n}<'b, SplitType> {{
        self.1.get_mut(k).map(|v| v.split{n}_mut().{nm1})
    }}
}}
\n", n=i, nm1=i-1, A=('A' as u8 + i - 1) as char, a=('a' as u8 + i - 1) as char));
    }

    write!(f, "\n")
}

pub fn build_split(out_dir: &String) -> Result<()> {
    let dest_path = Path::new(out_dir).join("split.rs");
    let mut f = File::create(&dest_path).unwrap();

    for i in 3..(MAX_TYPES+1) {
        try!(write!(f, "
/// Splits a `HashMap` into {n} disjoint hashmap references, able to access the split parts of the
/// stored `Splittable{n}` values independently.
pub fn split{n}<'a, K: 'a, V: 'a, S, SplitType>(v: &'a mut HashMap<K, V, S>) -> (", n=i));

        for j in 0..i {
            try!(write!(f, "HashMap{A}<'a, K, V, S, SplitType>, ", A=('A' as u8 + j) as char));
        }
        try!(write!(f, ")
where K: Eq + Hash, S: BuildHasher, V: Splittable{n}<'a, SplitType> {{
    let p = v as * mut _;
    (HashMapA(PhantomData, v)", n=i));

        for j in 1..i {
            try!(write!(f, ", HashMap{A}(PhantomData, unsafe {{ &mut*p }})", A=('A' as u8 + j) as char));
        }
        try!(write!(f, ")\n}}\n"));
    }

    write!(f, "\n")
}

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    build_trait(&out_dir).unwrap();
    build_helpers(&out_dir).unwrap();
    build_structs(&out_dir).unwrap();
    build_impls(&out_dir).unwrap();
    build_split(&out_dir).unwrap();
}