<commit_before>/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

extern crate core_graphics;
extern crate core_text;
extern crate core_foundation;
use core_graphics::base::{kCGImageAlphaNoneSkipFirst};
use core_foundation::string::UniChar;
use core_foundation::base::CFIndex;
use core_graphics::color_space::CGColorSpace;
use core_graphics::context::CGContext;
use core_graphics::font::{CGFont, CGGlyph};
use core_graphics::geometry::CGPoint;
use core_text::font;
use std::mem;

#[test]
fn it_works() {
    let k = supports_LCD();
    assert!(k);
}

fn supports_LCD() -> bool {
    let mut cg_context = CGContext::create_bitmap_context(1, 1, 8, 4,
                                                          &CGColorSpace::create_device_rgb(),
                                                          kCGImageAlphaNoneSkipFirst |
                                                          (2 << 12) //kCGBitmapByteOrder32Little
                                                          );
    let ct_font = font::new_from_name("Helvetica", 16.).unwrap();
    cg_context.set_should_smooth_fonts(true);
    cg_context.set_should_antialias(true);
    cg_context.set_allows_font_smoothing(true);
    //cg_context.set_text_drawing_mode(
    cg_context.set_rgb_fill_color(1.0, 1.0, 1.0, 1.0);
    let point = CGPoint {x: -1., y: 0.};
    let characters: [UniChar; 1] = ['|' as UniChar];
    let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph];
    let count: CFIndex = 1;
    ct_font.get_glyphs_for_characters(&characters[0], &mut glyphs[0], count);
    // XXX: it would be nice if we didn't have to clone cg_context here
    ct_font.draw_glyphs(&glyphs, &[point], cg_context.clone());
    let data = cg_context.data();
    let rgb : u32 = unsafe { std::mem::transmute::<[u8; 4], u32>([data[0],data[1],data[2],data[3]]) };
    let r = (rgb >> 16) & 0xFF;
    let g = (rgb >>  8) & 0xFF;
    let b = (rgb >>  0) & 0xFF;
    let supports_LCD = r != g || r != b;
    supports_LCD
}

pub trait ColorSpaceLuminance {
	fn to_luma(&self, gamma: f32, luminance: f32) -> f32;
	fn from_luma(&self, gamma: f32, luma: f32) -> f32;
}

pub struct SRGBColorSpaceLuminance
{
}

pub struct LinearColorSpaceLuminance
{
}

pub struct GammaColorSpaceLuminance
{}

impl ColorSpaceLuminance for LinearColorSpaceLuminance {
	fn to_luma(&self, gamma: f32, luminance: f32) -> f32 {
        assert!(gamma == 1.);
		luminance
	}
	fn from_luma(&self, gamma: f32, luma: f32) -> f32 {
        assert!(gamma == 1.);
		luma
	}
}

impl ColorSpaceLuminance for GammaColorSpaceLuminance {
	fn to_luma(&self, gamma: f32, luminance: f32) -> f32 {
		luminance.powf(gamma)
	}
	fn from_luma(&self, gamma: f32, luma: f32) -> f32 {
		luma.powf(1./gamma)
	}
}

impl ColorSpaceLuminance for SRGBColorSpaceLuminance {
	fn to_luma(&self, gamma: f32, luminance: f32) -> f32 {
        assert!(gamma == 0.);
        //The magic numbers are derived from the sRGB specification.
        //See http://www.color.org/chardata/rgb/srgb.xalter .
		if luminance <= 0.04045 {
			return luminance / 12.92;
		}
		return ((luminance + 0.055) / 1.055).powf(2.4);
	}
	fn from_luma(&self, gamma: f32, luma: f32) -> f32 {
        assert!(gamma == 0.);
        //The magic numbers are derived from the sRGB specification.
        //See http://www.color.org/chardata/rgb/srgb.xalter .
        if luma <= 0.0031308 {
            return luma * 12.92;
        }
        return 1.055 * luma.powf(1./2.4)
               - 0.055;
	}
}

fn round_to_u8(x : f32) -> u8
{
    assert!((x + 0.5).floor() < 256.0);
    (x + 0.5).floor() as u8
}

/**
 * A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise.
 * With lower values small text appears washed out (though correctly so).
 * With higher values lcd fringing is worse and the smoothing effect of
 * partial coverage is diminished.
 */
//rec->setContrast(0.5f);

fn apply_contrast(srca: f32, contrast: f32) -> f32 {
    srca + ((1.0 - srca) * contrast * srca)
}

// The approach here is not necessarily the one with the lowest error
// See https://bel.fi/alankila/lcd/alpcor.html for a similar kind of thing
// that just search for the adjusted alpha value
pub fn build_gamma_correcting_lut(table: &mut [u8; 256], src: u8, contrast: f32,
                                       src_space: &ColorSpaceLuminance, src_gamma: f32,
                                       dst_convert: &ColorSpaceLuminance, dst_gamma: f32) {

    let src = src as f32 / 255.0;
    let lin_src = src_space.to_luma(src_gamma, src);
    //Guess at the dst. The perceptual inverse provides smaller visual
    //discontinuities when slight changes to desaturated colors cause a channel
    //to map to a different correcting lut with neighboring srcI.
    //See https://code.google.com/p/chromium/issues/detail?id=141425#c59 .
    let dst = 1.0 - src;
    let lin_dst = dst_convert.to_luma(dst_gamma, dst);

    //Contrast value tapers off to 0 as the src luminance becomes white
    let adjusted_contrast = contrast * lin_dst;

    //Remove discontinuity and instability when src is close to dst.
    //The value 1/256 is arbitrary and appears to contain the instability.
    if (src - dst).abs() < (1.0 / 256.0) {
        let mut ii : f32 = 0.0;
        for i in 0..256 {
            let raw_srca = ii / 255.0;
            let srca = apply_contrast(raw_srca, adjusted_contrast);

            table[i] = round_to_u8(255.0 * srca);
            ii += 1.0;
        }
    } else {
        // Avoid slow int to float conversion.
        let mut ii : f32 = 0.0;
        for i in 0..256 {
            // 'raw_srca += 1.0f / 255.0f' and even
            // 'raw_srca = i * (1.0f / 255.0f)' can add up to more than 1.0f.
            // When this happens the table[255] == 0x0 instead of 0xff.
            // See http://code.google.com/p/chromium/issues/detail?id=146466
            let raw_srca = ii / 255.0;
            let srca = apply_contrast(raw_srca, adjusted_contrast);
            assert!(srca <= 1.0);
            let dsta = 1.0 - srca;

            // Calculate the output we want.
            let lin_out = lin_src * srca + dsta * lin_dst;
            assert!(lin_out <= 1.0);
            let out = dst_convert.from_luma(dst_gamma, lin_out);

            // Undo what the blit blend will do.
            // i.e. given the formula for OVER: out = src * result + (1 - result) * dst
            // solving for result gives:
            let result = (out - dst) / (src - dst);

            table[i] = round_to_u8(255.0 * result);

            ii += 1.0;
        }
    }
}

use std::cmp;

fn over(dst: u32, src: u32, alpha: u32) -> u32 {
    (src * alpha + dst * (255 - alpha))/255
}

fn overf(dst: f32, src: f32, alpha: f32) -> f32 {
    ((src * alpha + dst * (255. - alpha))/255.) as f32
}

fn absdiff(a: u32, b: u32) -> u32 {
    if a < b  { b - a } else { a - b }
}

#[test]
fn gamma() {
    let mut table: [u8; 256] = unsafe{ mem::uninitialized() } ;
    let space = GammaColorSpaceLuminance{};
    let g : f32 = 2.;
    let mut src : u32 = 131;
    while src < 256 {
        build_gamma_correcting_lut(&mut table, src as u8, 0., &space, g, &space, g);
        let mut max_diff = 0;
        let mut dst = 0;
        while dst < 256 {
            for alpha in 0u32..256 {
                let preblend = table[alpha as usize];
                let lin_dst = (dst as f32 / 255.).powf(g) * 255.;
                let lin_src = (src as f32 / 255.).powf(g) * 255.;

                let preblend_result = over(dst, src, preblend as u32);
                let true_result = ((overf(lin_dst, lin_src, alpha as f32) / 255.).powf(1. / g) * 255.) as u32;
                let diff = absdiff(preblend_result, true_result);
                //println!("{} -- {} {} = {}", alpha, preblend_result, true_result, diff);
                max_diff = cmp::max(max_diff, diff);
            }

            //println!("{} {} max {}", src, dst, max_diff);
            assert!(max_diff <= 33);
            dst += 1;

        }
        src += 1;
    }

}

<commit_msg>move out tests to it's own build configuration<commit_after>/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

pub trait ColorSpaceLuminance {
	fn to_luma(&self, gamma: f32, luminance: f32) -> f32;
	fn from_luma(&self, gamma: f32, luma: f32) -> f32;
}

pub struct SRGBColorSpaceLuminance
{
}

pub struct LinearColorSpaceLuminance
{
}

pub struct GammaColorSpaceLuminance
{}

impl ColorSpaceLuminance for LinearColorSpaceLuminance {
	fn to_luma(&self, gamma: f32, luminance: f32) -> f32 {
        assert!(gamma == 1.);
		luminance
	}
	fn from_luma(&self, gamma: f32, luma: f32) -> f32 {
        assert!(gamma == 1.);
		luma
	}
}

impl ColorSpaceLuminance for GammaColorSpaceLuminance {
	fn to_luma(&self, gamma: f32, luminance: f32) -> f32 {
		luminance.powf(gamma)
	}
	fn from_luma(&self, gamma: f32, luma: f32) -> f32 {
		luma.powf(1./gamma)
	}
}

impl ColorSpaceLuminance for SRGBColorSpaceLuminance {
	fn to_luma(&self, gamma: f32, luminance: f32) -> f32 {
        assert!(gamma == 0.);
        //The magic numbers are derived from the sRGB specification.
        //See http://www.color.org/chardata/rgb/srgb.xalter .
		if luminance <= 0.04045 {
			return luminance / 12.92;
		}
		return ((luminance + 0.055) / 1.055).powf(2.4);
	}
	fn from_luma(&self, gamma: f32, luma: f32) -> f32 {
        assert!(gamma == 0.);
        //The magic numbers are derived from the sRGB specification.
        //See http://www.color.org/chardata/rgb/srgb.xalter .
        if luma <= 0.0031308 {
            return luma * 12.92;
        }
        return 1.055 * luma.powf(1./2.4)
               - 0.055;
	}
}

fn round_to_u8(x : f32) -> u8
{
    assert!((x + 0.5).floor() < 256.0);
    (x + 0.5).floor() as u8
}

/**
 * A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise.
 * With lower values small text appears washed out (though correctly so).
 * With higher values lcd fringing is worse and the smoothing effect of
 * partial coverage is diminished.
 */
fn apply_contrast(srca: f32, contrast: f32) -> f32 {
    srca + ((1.0 - srca) * contrast * srca)
}

// The approach here is not necessarily the one with the lowest error
// See https://bel.fi/alankila/lcd/alpcor.html for a similar kind of thing
// that just search for the adjusted alpha value
pub fn build_gamma_correcting_lut(table: &mut [u8; 256], src: u8, contrast: f32,
                                  src_space: &ColorSpaceLuminance, src_gamma: f32,
                                  dst_convert: &ColorSpaceLuminance, dst_gamma: f32) {

    let src = src as f32 / 255.0;
    let lin_src = src_space.to_luma(src_gamma, src);
    // Guess at the dst. The perceptual inverse provides smaller visual
    // discontinuities when slight changes to desaturated colors cause a channel
    // to map to a different correcting lut with neighboring srcI.
    // See https://code.google.com/p/chromium/issues/detail?id=141425#c59 .
    let dst = 1.0 - src;
    let lin_dst = dst_convert.to_luma(dst_gamma, dst);

    // Contrast value tapers off to 0 as the src luminance becomes white
    let adjusted_contrast = contrast * lin_dst;

    // Remove discontinuity and instability when src is close to dst.
    // The value 1/256 is arbitrary and appears to contain the instability.
    if (src - dst).abs() < (1.0 / 256.0) {
        let mut ii : f32 = 0.0;
        for i in 0..256 {
            let raw_srca = ii / 255.0;
            let srca = apply_contrast(raw_srca, adjusted_contrast);

            table[i] = round_to_u8(255.0 * srca);
            ii += 1.0;
        }
    } else {
        // Avoid slow int to float conversion.
        let mut ii : f32 = 0.0;
        for i in 0..256 {
            // 'raw_srca += 1.0f / 255.0f' and even
            // 'raw_srca = i * (1.0f / 255.0f)' can add up to more than 1.0f.
            // When this happens the table[255] == 0x0 instead of 0xff.
            // See http://code.google.com/p/chromium/issues/detail?id=146466
            let raw_srca = ii / 255.0;
            let srca = apply_contrast(raw_srca, adjusted_contrast);
            assert!(srca <= 1.0);
            let dsta = 1.0 - srca;

            // Calculate the output we want.
            let lin_out = lin_src * srca + dsta * lin_dst;
            assert!(lin_out <= 1.0);
            let out = dst_convert.from_luma(dst_gamma, lin_out);

            // Undo what the blit blend will do.
            // i.e. given the formula for OVER: out = src * result + (1 - result) * dst
            // solving for result gives:
            let result = (out - dst) / (src - dst);

            table[i] = round_to_u8(255.0 * result);

            ii += 1.0;
        }
    }
}

#[cfg(test)]
mod tests {
    use std::cmp;
    use std::mem;

    fn over(dst: u32, src: u32, alpha: u32) -> u32 {
        (src * alpha + dst * (255 - alpha))/255
    }

    fn overf(dst: f32, src: f32, alpha: f32) -> f32 {
        ((src * alpha + dst * (255. - alpha))/255.) as f32
    }

    fn absdiff(a: u32, b: u32) -> u32 {
        if a < b  { b - a } else { a - b }
    }

    #[test]
    fn gamma() {
        let mut table: [u8; 256] = unsafe{ mem::uninitialized() } ;
        let space = ::GammaColorSpaceLuminance{};
        let g : f32 = 2.;
        let mut src : u32 = 131;
        while src < 256 {
            ::build_gamma_correcting_lut(&mut table, src as u8, 0., &space, g, &space, g);
            let mut max_diff = 0;
            let mut dst = 0;
            while dst < 256 {
                for alpha in 0u32..256 {
                    let preblend = table[alpha as usize];
                    let lin_dst = (dst as f32 / 255.).powf(g) * 255.;
                    let lin_src = (src as f32 / 255.).powf(g) * 255.;

                    let preblend_result = over(dst, src, preblend as u32);
                    let true_result = ((overf(lin_dst, lin_src, alpha as f32) / 255.).powf(1. / g) * 255.) as u32;
                    let diff = absdiff(preblend_result, true_result);
                    //println!("{} -- {} {} = {}", alpha, preblend_result, true_result, diff);
                    max_diff = cmp::max(max_diff, diff);
                }

                //println!("{} {} max {}", src, dst, max_diff);
                assert!(max_diff <= 33);
                dst += 1;

            }
            src += 1;
        }
    }
} // end mod
<|endoftext|>


<commit_before>#![feature(proc_macro)]

extern crate proc_macro;
extern crate syn;

#[macro_use]
extern crate quote;

use proc_macro::TokenStream;

use syn::*;

#[derive(Debug)]
enum BitFieldPosition {
    Single(u8),
    Range(std::ops::Range<u8>)
}

struct BitField {
    position: BitFieldPosition,
    ident: Ident,
    ty: Ty
}

/*
fn output_struct(name: &Ident, bitfields: &Vec<BitField>) -> quote::Tokens {
    let mut impl_body = quote! {};

    for bitfield in &bitfields.into_iter() {
        println!("field {} @{:?}", bitfield.ident, bitfield.position);
        let ident = bitfield.ident;
        let ty = bitfield.ty;

        impl_body = quote! {
            #impl_body
            get_#ident(&self) -> #ty {

            }
        }
    };

    quote! {
        struct #name (u8);
        impl #name {
            #impl_body
        }
    }
}
*/

#[proc_macro_attribute]
pub fn register(_: TokenStream, input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = parse_derive_input(&s).unwrap();

    let fields = match ast.body {
        Body::Enum(_) => panic!("enum not supported"),
        Body::Struct(x) => match x {
            VariantData::Struct(fields) => fields,
            _ => panic!("tuple and unit not supported")
        }
    };

    let mut bitfields: Vec<BitField> = vec![];

    let mut impl_body = quote! {};

    for field in &fields {
        let ident = field.ident.clone().unwrap();
        let ty_str = match &field.ty {
            &Ty::Path(_, ref path) => path.segments[0].ident.clone(),
            _ => panic!("only path types supported"),
        };

        let ty = field.clone().ty;

        let mut from: Option<u8> = None;
        let mut to: Option<u8> = None;
        let mut at: Option<u8> = None;

        for attr in &field.attrs {
            if let MetaItem::List(attr_ident, attr_nest) = attr.clone().value {
                if attr_ident == "bitfield" {
                    for attr_nest_item in &attr_nest {
                        match attr_nest_item.clone() {
                            NestedMetaItem::MetaItem(MetaItem::NameValue(nv_ident, Lit::Int(nv_value, _))) => {
                                match nv_ident.as_ref() {
                                    "at" => (at = Some(nv_value as u8)),
                                    "from" => (from = Some(nv_value as u8)),
                                    "to" => (to = Some(nv_value as u8)),
                                    _ => panic!("unsupported param name (use 'at' or 'from'/'to')"),
                                }
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        if (from.is_some() || to.is_some()) && at.is_some() {
            panic!("select 'at' or 'from'/'to' parameters, not both");
        }

        if from.is_some() ^ to.is_some() {
            panic!("select 'from' and 'to' parameters together");
        }

        if from.is_none() && to.is_none() && at.is_none() {
            panic!("select bit parameters (use #[bitfield(at=x or from=x to=y)])");
        }

        let position: BitFieldPosition = if from.is_some() && to.is_some() {
            BitFieldPosition::Range(std::ops::Range{start: from.unwrap(), end: to.unwrap()})
        } else {
            BitFieldPosition::Single(at.unwrap())
        };

        println!("field {} @{:?}: {}", ident, position, ty_str);

        // println!("field {} @{:?}", ident, position);

        let getter_str = format!("get_{}", ident.as_ref());
        let getter: Ident = From::from(getter_str.as_str());

        let setter_str = format!("set_{}", ident.as_ref());
        let setter: Ident = From::from(setter_str.as_str());

        match &position {
            &BitFieldPosition::Single(x) => {
                let mask: u8 = 1 << x;
                let nmask: u8 = !mask;

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        let raw: u8 = (self.0[0] & #mask) >> #x;
                        return std::convert::From::from(raw);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        let raw: u8 = std::convert::Into::into(value);
                        self.0[0] &= #nmask;
                        self.0[0] |= (raw & 1) << #x;
                    }
                }
            },
            &BitFieldPosition::Range(ref range) => {
                let from: u8 = range.start;
                let to = range.end;

                let size = to - from + 1;
                let type_mask: u8 = (1 << size) - 1;
                let mask: u8 = type_mask << from;
                let nmask: u8 = !mask;

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        let raw: u8 = (self.0[0] & #mask) >> #from;
                        return std::convert::From::from(raw);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        let raw: u8 = std::convert::Into::into(value);
                        self.0[0] &= #nmask;
                        self.0[0] |= (raw & #type_mask) << #from;
                    }
                }
            },
        };

        bitfields.push(BitField {position: position, ident: ident, ty: ty});
    }

    let name = &ast.ident;

    return (quote! {
        struct #name ([u8;3]);
        impl Default for #name {
            fn default() -> Self {
                return #name ([0,0,0]);
            }
        }
        impl #name {

            #impl_body
        }
    }).parse().unwrap();

    // return input;
    // return output_struct(&ast.ident, &bitfields).parse().unwrap();
}

/*
Struct(
    Struct([
        Field {
            ident: Some(Ident("foo")),
            vis: Inherited,
            attrs: [
                Attribute {
                    style: Outer,
                    value: List(
                        Ident("bitfield"),
                        [
                            MetaItem(
                                NameValue(
                                    Ident("at"), Int(0, Unsuffixed)
                                )
                            )
                        ]
                    ),
                    is_sugared_doc: false
                }
            ],
            ty: Path(
                None,
                Path {
                    global: false,
                    segments: [
                        PathSegment {
                            ident: Ident("u8"),
                            parameters: AngleBracketed(
                                AngleBracketedParameterData {
                                    lifetimes: [],
                                    types: [],
                                    bindings: []
                                }
                            )
                        }
                    ]
                }
            )
        }
    ])
)
*/<commit_msg>proper work with array size<commit_after>#![feature(proc_macro)]

extern crate proc_macro;
use proc_macro::TokenStream;

extern crate syn;
use syn::*;

#[macro_use]
extern crate quote;

#[derive(Debug)]
enum BitFieldPosition {
    Single(u8),
    Range(std::ops::Range<u8>)
}

#[derive(Debug)]
struct BitField {
    position: BitFieldPosition,
    ident: Ident,
    ty: Ty
}

fn output_struct(name: &Ident, bitfields: &Vec<BitField>) -> quote::Tokens {
    let mut impl_body = quote! {};

    let starts: Vec<u8> = bitfields.iter().map(|x| match &x.position {
        &BitFieldPosition::Single(x) => x,
        &BitFieldPosition::Range(ref range) => range.start
    }).collect();

    let max_starts = starts.iter().fold(None, |max, x| match max {
        None => Some(x),
        Some(y) => Some(std::cmp::max(x, y))
    }).unwrap();

    let base_size: usize = (*max_starts as usize / 8) + 1;

    for bitfield in bitfields {
        println!("iter field {} @{:?}", bitfield.ident, bitfield.position);

        let getter_str = format!("get_{}", bitfield.ident.as_ref());
        let getter: Ident = From::from(getter_str.as_str());

        let setter_str = format!("set_{}", bitfield.ident.as_ref());
        let setter: Ident = From::from(setter_str.as_str());

        let ty = &bitfield.ty;

        match &bitfield.position {
            &BitFieldPosition::Single(x) => {
                let mask: u8 = 1 << (x % 8);
                let nmask: u8 = !mask;

                let byteidx: usize = x as usize / 8;

                let shift = x % 8;

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        let raw: u8 = (self.0[#byteidx] & #mask) >> #shift;
                        return std::convert::From::from(raw);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        let raw: u8 = std::convert::Into::into(value);
                        self.0[#byteidx] &= #nmask;
                        self.0[#byteidx] |= (raw & 1) << #shift;
                    }
                }
            },
            &BitFieldPosition::Range(ref range) => {
                let from = range.start;
                let to = range.end;

                let size = to - from + 1;
                let type_mask: u8 = (1 << size) - 1;
                let mask: u8 = type_mask << (from % 8);
                let nmask: u8 = !mask;

                let byteidx: usize = from as usize / 8;

                let shift = from % 8;

                impl_body = quote! {
                    #impl_body

                    pub fn #getter(&self) -> #ty {
                        let raw: u8 = (self.0[#byteidx] & #mask) >> #shift;
                        return std::convert::From::from(raw);
                    }

                    pub fn #setter(&mut self, value: #ty) {
                        let raw: u8 = std::convert::Into::into(value);
                        self.0[#byteidx] &= #nmask;
                        self.0[#byteidx] |= (raw & #type_mask) << #shift;
                    }
                }
            },
        }
    };

    return quote! {
        struct #name ([u8;#base_size]);
        impl Default for #name {
            fn default() -> Self {
                return #name ([0;#base_size]);
            }
        }
        impl #name {

            #impl_body
        }
    }
}

#[proc_macro_attribute]
pub fn register(_: TokenStream, input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = parse_derive_input(&s).unwrap();

    let fields = match ast.body {
        Body::Enum(_) => panic!("enum not supported"),
        Body::Struct(x) => match x {
            VariantData::Struct(fields) => fields,
            _ => panic!("tuple and unit not supported")
        }
    };

    #[derive(Debug)]
    let mut bitfields: Vec<BitField> = vec![];

    for field in &fields {
        let ty = field.clone().ty;

        let mut from: Option<u8> = None;
        let mut to: Option<u8> = None;
        let mut at: Option<u8> = None;

        for attr in &field.attrs {
            if let MetaItem::List(attr_ident, attr_nest) = attr.clone().value {
                if attr_ident == "bitfield" {
                    for attr_nest_item in &attr_nest {
                        match attr_nest_item.clone() {
                            NestedMetaItem::MetaItem(MetaItem::NameValue(nv_ident, Lit::Int(nv_value, _))) => {
                                match nv_ident.as_ref() {
                                    "at" => (at = Some(nv_value as u8)),
                                    "from" => (from = Some(nv_value as u8)),
                                    "to" => (to = Some(nv_value as u8)),
                                    _ => panic!("unsupported param name (use 'at' or 'from'/'to')"),
                                }
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        if (from.is_some() || to.is_some()) && at.is_some() {
            panic!("select 'at' or 'from'/'to' parameters, not both");
        }

        if from.is_some() ^ to.is_some() {
            panic!("select 'from' and 'to' parameters together");
        }

        if from.is_none() && to.is_none() && at.is_none() {
            panic!("select bit parameters (use #[bitfield(at=x or from=x to=y)])");
        }

        let position: BitFieldPosition = if from.is_some() && to.is_some() {
            BitFieldPosition::Range(std::ops::Range{start: from.unwrap(), end: to.unwrap()})
        } else {
            BitFieldPosition::Single(at.unwrap())
        };

        let ident = field.ident.clone().unwrap();
        let ty_str = match &field.ty {
            &Ty::Path(_, ref path) => path.segments[0].ident.clone(),
            _ => panic!("only path types supported"),
        };

        println!("field {} @{:?}: {}", ident, position, ty_str);

        bitfields.push(BitField {position: position, ident: ident, ty: ty});
    }

    let name = &ast.ident;

    return output_struct(name, &bitfields).parse().unwrap();
}<|endoftext|>


<commit_before>#![no_std]

pub mod prelude;

// TODO documentation
// TODO attributes
// TODO MACROS
#[macro_export] macro_rules! lisp {
    // empty
    () => (());
    (()) => (());

    // special forms
    ((ns $($ns_form:tt)*) $($body:tt)*) => {
        $(lisp!($ns_form);)*
        $(lisp!($body);)*
    };
    ((extern [$($krate:tt)*])) => {
        $(lisp!(@krate $krate);)*
    };
    ((use [$($uze:tt)*])) => {
        $(lisp!(@uze $uze);)*
    };
    ((lambda ($($argn:ident)*) $($body:tt)*)) => {
        // regular lambda
        |$($argn),*| { $(lisp!($body));* }
    };
    ((lambda (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {
        // regular lambda
        |$($argn:$argt),*| -> $ret { $(lisp!($body));* }
    };
    ((lambda $s:ident (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {{
        // recursive lambda
        // $s MUST NOT be "self"
        // recurse by calling ($s ...)
        // FIXME recursive lambdas can't capture variables

        lisp!((rust { fn $s($($argn: $argt),*) -> $ret { $(lisp!($body));* } $s }))
    }};
    ((defn $name:ident (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {
        fn $name($($argn:$argt),*) -> $ret { $(lisp!($body));* }
    };
    ((if $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    (@list while, $cond:tt, $($body:tt),*) => {
        while lisp!($cond) { $(lisp!($body));* }
    };
    // TODO for loops
    (@list match, $var:tt, $(($cond:tt $arm:tt)),*) => {
        match lisp!($var) {
            $(lisp!(@pat $cond) => lisp!($arm)),*
        }
    };
    ((do $($stmts:tt)*)) => {{
        $(lisp!($stmts));*
    }};

    // variables
    ((let ((mut $var:ident $val:tt) $($bindings:tt)+) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        lisp!((let ($($bindings)+) $($body)*))
    }};
    ((let (($var:ident $val:tt) $($bindings:tt)+) $($body:tt)*)) => {{
        let $var = lisp!($val);
        lisp!((let ($($bindings)+) $($body)*))
    }};
    ((let ((mut $var:ident $val:tt)) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((let ((mut $var:ident $val:tt)) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((let (($var:ident $val:tt)) $($body:tt)*)) => {{
        let $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((:= $var:ident $val:tt)) => {
        $var = lisp!($val);
    };

    // escape hatch
    ((rust $body:block)) => {
        { $body }
    };

    // list parsing
    (($($elem:tt)*)) => {
        lisp!(@list $($elem),*)
    };

    // parsers for unary and binary operators
    (@list -,    $arg:tt   ) => { lisp!(@unary  _neg,   $arg   ) };
    (@list !,    $arg:tt   ) => { lisp!(@unary  _not,   $arg   ) };
    (@list +,  $($arg:tt),*) => { lisp!(@binary _add, $($arg),*) };
    (@list &,  $($arg:tt),*) => { lisp!(@binary _and, $($arg),*) };
    (@list |,  $($arg:tt),*) => { lisp!(@binary _or,  $($arg),*) };
    (@list ^,  $($arg:tt),*) => { lisp!(@binary _xor, $($arg),*) };
    (@list /,  $($arg:tt),*) => { lisp!(@binary _div, $($arg),*) };
    (@list *,  $($arg:tt),*) => { lisp!(@binary _mul, $($arg),*) };
    (@list %,  $($arg:tt),*) => { lisp!(@binary _rem, $($arg),*) };
    (@list <<, $($arg:tt),*) => { lisp!(@binary _shl, $($arg),*) };
    (@list >>, $($arg:tt),*) => { lisp!(@binary _shr, $($arg),*) };
    (@list -,  $($arg:tt),*) => { lisp!(@binary _sub, $($arg),*) };
    (@list ==, $($arg:tt),*) => { lisp!(@binary _eq,  $($arg),*) };
    (@list !=, $($arg:tt),*) => { lisp!(@binary _ne,  $($arg),*) };
    (@list >,  $($arg:tt),*) => { lisp!(@binary _gt,  $($arg),*) };
    (@list <,  $($arg:tt),*) => { lisp!(@binary _lt,  $($arg),*) };
    (@list >=, $($arg:tt),*) => { lisp!(@binary _ge,  $($arg),*) };
    (@list <=, $($arg:tt),*) => { lisp!(@binary _le,  $($arg),*) };

    // generically turn unary/binary operators into function calls
    // binary operators can be used as n-ary operators through @reduce
    (@unary  $op:ident, $a:tt)        => { lisp!(@list $op, $a)     };
    (@binary $op:ident, $a:tt, $b:tt) => { lisp!(@list $op, $a, $b) };
    (@binary $op:ident, $a:tt, $b:tt, $($rest:tt),+) =>
                                               { lisp!(@reduce $op,
                                                       ($op $a $b),
                                                       $($rest),+) };

    // reduce implementation
    // TODO external entry point for @reduce
    (@reduce $op:ident, $acc:tt)                       => { lisp!($acc)          };
    (@reduce $op:ident, $acc:tt, $a:tt)                => { lisp!(@reduce $op,
                                                                  ($op $acc $a)) };
    (@reduce $op:ident, $acc:tt, $a:tt, $($rest:tt),+) => { lisp!(@reduce $op,
                                                                  ($op $acc $a),
                                                                  $($rest),+)    };
    // ns form helpers
    (@krate $(^$attr:meta)* $krate:ident) => {
        $(#[$attr:meta])*
        extern crate $krate;
    };
    (@krate $(^$attr:meta)* ($krate:ident $alias:ident)) => {
        $(#[$attr:meta])*
        extern crate $krate as $alias;
    };
    (@uze ($($head:ident)*)) => { use $($head)::*; };
    (@uze ($($head:ident)* { $($multiple:ident)* })) => {
        lisp!(@uze mult ($($head)*) { $($multiple)* });
    };
    (@uze mult $head:tt { $($multiple:ident)* }) => {
        $(lisp!(@uze mult out $head $multiple);)*
    };
    (@uze mult out ($($head:ident)*) $multiple:ident) => {
        use $($head)::*::$multiple;
    };

    // macro calls
    (@list $mac:ident, !) => {
        $mac!()
    };
    (@list $mac:ident, !, $($arg:tt),*) => {
        $mac!($(lisp!($arg)),*)
    };

    // struct constructors
    (@list $name:ident, ., $(($member:ident $val:tt)),*) => {
        $name { $($member: lisp!($val))* }
    };

    // function calls
    (@list $name:expr) => {
        lisp!($name)()
    };
    (@list $name:expr, $($arg:tt),*) => {
        lisp!($name)($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);
}
<commit_msg>add impls, impl items, structs, type aliases<commit_after>#![no_std]

pub mod prelude;

// TODO documentation
// TODO attributes
// TODO MACROS
#[macro_export] macro_rules! lisp {
    // empty
    () => (());
    (()) => (());

    // special forms
    ((ns $($ns_form:tt)*) $($body:tt)*) => {
        $(lisp!($ns_form);)*
        $(lisp!($body);)*
    };
    ((extern [$($krate:tt)*])) => {
        $(lisp!(@krate $krate);)*
    };
    ((use [$($uze:tt)*])) => {
        $(lisp!(@uze $uze);)*
    };
    ((lambda ($($argn:ident)*) $($body:tt)*)) => {
        // regular lambda
        |$($argn),*| { $(lisp!($body));* }
    };
    ((lambda (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {
        // regular lambda
        |$($argn:$argt),*| -> $ret { $(lisp!($body));* }
    };
    ((lambda $s:ident (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {{
        // recursive lambda
        // $s MUST NOT be "self"
        // recurse by calling ($s ...)
        // FIXME recursive lambdas can't capture variables

        lisp!((rust { fn $s($($argn: $argt),*) -> $ret { $(lisp!($body));* } $s }))
    }};
    ((defn $name:ident () $($body:tt)*)) => {
        fn $name() {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&$selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&$selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&mut $selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&mut $selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident: Box<Self>) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph: Box<Self> $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($($argn:$argt),*) -> $ret {
            $(lisp!($body));*
        }
    };

    ((defstruct $name:ident $(($typ:ty))*)) => {
        struct $name($($typ),*);
    };
    ((defstruct $name:ident $(($field:ident $typ:ty))*)) => {
        struct $name { $($field: $typ),* }
    };
    ((defstruct $name:ident <$($gen:ident)*>)) => {
        struct $name<$($gen),*>;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($typ:ty))*)) => {
        struct $name<$($gen),*>($($typ),*) where $($wty: $($wtr)*),*;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($field:ident $typ:ty))*)) => {
        struct $name<$($gen),*> where $($wty: $($wtr)*),* { $($field: $typ),* }
    };

    ((deftype $name:ident $typ:ty)) => { type $name = $typ; };
    ((deftype $name:ident <$($gen:ident)*> $typ:ty)) => { type $name<$($gen),*> = $typ; };

    ((defimpl ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl $trate for $typ {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) (where $(($wty:ident $($wtr:tt)*))*) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };

    ((if $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    (@list while, $cond:tt, $($body:tt),*) => {
        while lisp!($cond) { $(lisp!($body));* }
    };
    // TODO for loops
    (@list match, $var:tt, $(($cond:tt $arm:tt)),*) => {
        match lisp!($var) {
            $(lisp!(@pat $cond) => lisp!($arm)),*
        }
    };
    ((do $($stmts:tt)*)) => {{
        $(lisp!($stmts));*
    }};

    // variables
    ((let ((mut $var:ident $val:tt) $($bindings:tt)+) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        lisp!((let ($($bindings)+) $($body)*))
    }};
    ((let (($var:ident $val:tt) $($bindings:tt)+) $($body:tt)*)) => {{
        let $var = lisp!($val);
        lisp!((let ($($bindings)+) $($body)*))
    }};
    ((let ((mut $var:ident $val:tt)) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((let ((mut $var:ident $val:tt)) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((let (($var:ident $val:tt)) $($body:tt)*)) => {{
        let $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((:= $var:ident $val:tt)) => {
        $var = lisp!($val);
    };

    // escape hatch
    ((rust $body:block)) => {
        { $body }
    };

    // list parsing
    (($($elem:tt)*)) => {
        lisp!(@list $($elem),*)
    };

    // parsers for unary and binary operators
    (@list -,    $arg:tt   ) => { lisp!(@unary  _neg,   $arg   ) };
    (@list !,    $arg:tt   ) => { lisp!(@unary  _not,   $arg   ) };
    (@list +,  $($arg:tt),*) => { lisp!(@binary _add, $($arg),*) };
    (@list &,  $($arg:tt),*) => { lisp!(@binary _and, $($arg),*) };
    (@list |,  $($arg:tt),*) => { lisp!(@binary _or,  $($arg),*) };
    (@list ^,  $($arg:tt),*) => { lisp!(@binary _xor, $($arg),*) };
    (@list /,  $($arg:tt),*) => { lisp!(@binary _div, $($arg),*) };
    (@list *,  $($arg:tt),*) => { lisp!(@binary _mul, $($arg),*) };
    (@list %,  $($arg:tt),*) => { lisp!(@binary _rem, $($arg),*) };
    (@list <<, $($arg:tt),*) => { lisp!(@binary _shl, $($arg),*) };
    (@list >>, $($arg:tt),*) => { lisp!(@binary _shr, $($arg),*) };
    (@list -,  $($arg:tt),*) => { lisp!(@binary _sub, $($arg),*) };
    (@list ==, $($arg:tt),*) => { lisp!(@binary _eq,  $($arg),*) };
    (@list !=, $($arg:tt),*) => { lisp!(@binary _ne,  $($arg),*) };
    (@list >,  $($arg:tt),*) => { lisp!(@binary _gt,  $($arg),*) };
    (@list <,  $($arg:tt),*) => { lisp!(@binary _lt,  $($arg),*) };
    (@list >=, $($arg:tt),*) => { lisp!(@binary _ge,  $($arg),*) };
    (@list <=, $($arg:tt),*) => { lisp!(@binary _le,  $($arg),*) };

    // generically turn unary/binary operators into function calls
    // binary operators can be used as n-ary operators through @reduce
    (@unary  $op:ident, $a:tt)        => { lisp!(@list $op, $a)     };
    (@binary $op:ident, $a:tt, $b:tt) => { lisp!(@list $op, $a, $b) };
    (@binary $op:ident, $a:tt, $b:tt, $($rest:tt),+) =>
                                               { lisp!(@reduce $op,
                                                       ($op $a $b),
                                                       $($rest),+) };

    // reduce implementation
    // TODO external entry point for @reduce
    (@reduce $op:ident, $acc:tt)                       => { lisp!($acc)          };
    (@reduce $op:ident, $acc:tt, $a:tt)                => { lisp!(@reduce $op,
                                                                  ($op $acc $a)) };
    (@reduce $op:ident, $acc:tt, $a:tt, $($rest:tt),+) => { lisp!(@reduce $op,
                                                                  ($op $acc $a),
                                                                  $($rest),+)    };
    // ns form helpers
    (@krate $(^$attr:meta)* $krate:ident) => {
        $(#[$attr:meta])*
        extern crate $krate;
    };
    (@krate $(^$attr:meta)* ($krate:ident $alias:ident)) => {
        $(#[$attr:meta])*
        extern crate $krate as $alias;
    };
    (@uze ($($head:ident)*)) => { use $($head)::*; };
    (@uze ($($head:ident)* { $($multiple:ident)* })) => {
        lisp!(@uze mult ($($head)*) { $($multiple)* });
    };
    (@uze mult $head:tt { $($multiple:ident)* }) => {
        $(lisp!(@uze mult out $head $multiple);)*
    };
    (@uze mult out ($($head:ident)*) $multiple:ident) => {
        use $($head)::*::$multiple;
    };

    // macro calls
    (@list $mac:ident, !) => {
        $mac!()
    };
    (@list $mac:ident, !, $($arg:tt),*) => {
        $mac!($(lisp!($arg)),*)
    };

    // struct constructors
    (@list $name:ident, ., $(($member:ident $val:tt)),*) => {
        $name { $($member: lisp!($val))* }
    };

    // function calls
    (@list $name:expr) => {
        lisp!($name)()
    };
    (@list $name:expr, $($arg:tt),*) => {
        lisp!($name)($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

enum DomainOrIPAddressLiteral<'a> {
    ADomain(Domain<'a>),
    IPAddressLiteral(&'a str),
}

// TODO: Better type:
type Domain<'a> = &'a str;

type Postmaster = String;
fn postmaster() {
    "Postmaster";
}

enum AddressOrPostmaster<'a> {
    AnAddress(Address<'a>),
    Postmaster,
}

struct Address<'a> {
    local_part: &'a str, // TODO: own type
    domain: Domain<'a>,
}

enum OneOrMore<T> {
    One(T),
    More(T,Box<OneOrMore<T>>),
}

enum ProtocolExtension {
    EightBitMIME,
}

struct Envelope<'a> {
    originator: Address<'a>,
    recipients: OneOrMore<Address<'a>>,
    protocol_extensions: Vec<ProtocolExtension>
}

struct Header<'a> {
    fields: BTreeMap<&'a str, &'a str> // Case-insensitivity
}

struct Content<'a> {
    header: Header<'a>,
    body: &'a str, // TODO: own type
}

struct MailObject<'a> {
    envelope: Envelope<'a>,
    content: Content<'a>,
}

type ReversePath = String;
type MailParameter = String;
type RecipientParameter = String;

enum SMTPCommand<'a> {
    Hello(Domain<'a>),
    ExtendedHello(DomainOrIPAddressLiteral<'a>),
    Mail(ReversePath, Vec<MailParameter>),
    Recipient(Vec<AddressOrPostmaster<'a>>, Vec<RecipientParameter>),
    Data,
    Reset,
    Verify(String),
    Expand(String),
    Help(Option<String>),
    NoOp(Option<String>),
    Quit,
}

type ExtendedHelloGreet = String;

type ExtendedHelloLine = String;

enum SMTPResponse<'a> {
    ExtendedHelloOkResponse(Domain<'a>, Option<ExtendedHelloGreet>, Vec<ExtendedHelloLine>),
}

#[test]
fn it_works() {
    let mail_object = MailObject {
        envelope: Envelope {
            originator: Address {
                local_part: "kyle.marek.spartz",
                domain: "gmail.com",
            },
            recipients: OneOrMore::More(Address {
                    local_part: "zeckalpha",
                    domain: "gmail.com",
                }, Box::new(OneOrMore::One(Address {
                    local_part: "kyle",
                    domain: "marek-spartz.org",
                }))
            ),
            protocol_extensions: vec![
                ProtocolExtension::EightBitMIME,
            ]
        },
        content: Content {
            header: Header {
                fields: {
                    let mut fields = BTreeMap::new();
                    fields.insert("orig-date", "...");
                    fields.insert("from", "kyle.marek.spartz@gmail.com");
                    fields
                }
            },
            body: "LOL"
        }
    };
    assert_eq!("LOL", mail_object.content.body);
}
<commit_msg>Incremental work on writing to a tcp stream<commit_after>use std::collections::BTreeMap;
use std::io::prelude::*;
use std::fs::File;

enum DomainOrIPAddressLiteral<'a> {
    ADomain(Domain<'a>),
    IPAddressLiteral(&'a str),
}

// TODO: Better type:
type Domain<'a> = &'a str;

type Postmaster = String;
fn postmaster() {
    "Postmaster";
}

enum AddressOrPostmaster<'a> {
    AnAddress(Address<'a>),
    Postmaster,
}

struct Address<'a> {
    local_part: &'a str, // TODO: own type
    domain: Domain<'a>,
}

enum OneOrMore<T> {
    One(T),
    More(T,Box<OneOrMore<T>>),
}

enum ProtocolExtension {
    EightBitMIME,
}

struct Envelope<'a> {
    originator: Address<'a>,
    recipients: OneOrMore<Address<'a>>,
    protocol_extensions: Vec<ProtocolExtension>
}

struct Header<'a> {
    fields: BTreeMap<&'a str, &'a str> // Case-insensitivity
}

struct Content<'a> {
    header: Header<'a>,
    body: &'a str, // TODO: own type
}

struct MailObject<'a> {
    envelope: Envelope<'a>,
    content: Content<'a>,
}

type ReversePath = String;
type MailParameter = String;
type RecipientParameter = String;

enum SMTPCommand<'a> {
    Hello(Domain<'a>),
    ExtendedHello(DomainOrIPAddressLiteral<'a>),
    Mail(ReversePath, Vec<MailParameter>),
    Recipient(Vec<AddressOrPostmaster<'a>>, Vec<RecipientParameter>),
    Data,
    Reset,
    Verify(String),
    Expand(String),
    Help(Option<String>),
    NoOp(Option<String>),
    Quit,
}

fn helo(stream: Write) -> std::io::Result<usize> {
  let mut helo_string = "HELO";
  stream.write(helo_string);
}

type ExtendedHelloGreet = String;

type ExtendedHelloLine = String;

enum SMTPResponse<'a> {
    ExtendedHelloOkResponse(Domain<'a>, Option<ExtendedHelloGreet>, Vec<ExtendedHelloLine>),
}

#[test]
fn it_works() {
    let mail_object = MailObject {
        envelope: Envelope {
            originator: Address {
                local_part: "kyle.marek.spartz",
                domain: "gmail.com",
            },
            recipients: OneOrMore::More(Address {
                    local_part: "zeckalpha",
                    domain: "gmail.com",
                }, Box::new(OneOrMore::One(Address {
                    local_part: "kyle",
                    domain: "marek-spartz.org",
                }))
            ),
            protocol_extensions: vec![
                ProtocolExtension::EightBitMIME,
            ]
        },
        content: Content {
            header: Header {
                fields: {
                    let mut fields = BTreeMap::new();
                    fields.insert("orig-date", "...");
                    fields.insert("from", "kyle.marek.spartz@gmail.com");
                    fields
                }
            },
            body: "LOL"
        }
    };
    assert_eq!("LOL", mail_object.content.body);
}

#[test]
fn helo_writes() {
    let mut stream = try!(File::create("helo_output"));
    let mut content = String::new();
    helo(stream);
    stream.read_to_string(&mut content);
    assert_eq!("HELO", content);
}
<|endoftext|>


<commit_before><commit_msg>Generate the lib from new svd<commit_after><|endoftext|>


<commit_before>//! Zero-cost Futures in Rust
//!
//! This library is an implementation of futures in Rust which aims to provide
//! a robust implementation of handling asynchronous computations, ergonomic
//! composition and usage, and zero-cost abstractions over what would otherwise
//! be written by hand.
//!
//! Futures are a concept for an object which is a proxy for another value that
//! may not be ready yet. For example issuing an HTTP request may return a
//! future for the HTTP response, as it probably hasn't arrived yet. With an
//! object representing a value that will eventually be available, futures allow
//! for powerful composition of tasks through basic combinators that can perform
//! operations like chaining computations, changing the types of futures, or
//! waiting for two futures to complete at the same time.
//!
//! ## Installation
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! futures = "0.1"
//! ```
//!
//! ## Examples
//!
//! Let's take a look at a few examples of how futures might be used:
//!
//! ```
//! extern crate futures;
//!
//! use std::io;
//! use std::time::Duration;
//! use futures::{Future, Map};
//!
//! // A future is actually a trait implementation, so we can generically take a
//! // future of any integer and return back a future that will resolve to that
//! // value plus 10 more.
//! //
//! // Note here that like iterators, we're returning the `Map` combinator in
//! // the futures crate, not a boxed abstraction. This is a zero-cost
//! // construction of a future.
//! fn add_ten<F>(future: F) -> Map<F, fn(i32) -> i32>
//!     where F: Future<Item=i32>,
//! {
//!     fn add(a: i32) -> i32 { a + 10 }
//!     future.map(add)
//! }
//!
//! // Not only can we modify one future, but we can even compose them together!
//! // Here we have a function which takes two futures as input, and returns a
//! // future that will calculate the sum of their two values.
//! //
//! // Above we saw a direct return value of the `Map` combinator, but
//! // performance isn't always critical and sometimes it's more ergonomic to
//! // return a trait object like we do here. Note though that there's only one
//! // allocation here, not any for the intermediate futures.
//! fn add<'a, A, B>(a: A, b: B) -> Box<Future<Item=i32, Error=A::Error> + 'a>
//!     where A: Future<Item=i32> + 'a,
//!           B: Future<Item=i32, Error=A::Error> + 'a,
//! {
//!     Box::new(a.join(b).map(|(a, b)| a + b))
//! }
//!
//! // Futures also allow chaining computations together, starting another after
//! // the previous finishes. Here we wait for the first computation to finish,
//! // and then decide what to do depending on the result.
//! fn download_timeout(url: &str,
//!                     timeout_dur: Duration)
//!                     -> Box<Future<Item=Vec<u8>, Error=io::Error>> {
//!     use std::io;
//!     use std::net::{SocketAddr, TcpStream};
//!
//!     type IoFuture<T> = Box<Future<Item=T, Error=io::Error>>;
//!
//!     // First thing to do is we need to resolve our URL to an address. This
//!     // will likely perform a DNS lookup which may take some time.
//!     let addr = resolve(url);
//!
//!     // After we acquire the address, we next want to open up a TCP
//!     // connection.
//!     let tcp = addr.and_then(|addr| connect(&addr));
//!
//!     // After the TCP connection is established and ready to go, we're off to
//!     // the races!
//!     let data = tcp.and_then(|conn| download(conn));
//!
//!     // That all might take awhile, though, so let's not wait too long for it
//!     // to all come back. The `select` combinator here returns a future which
//!     // resolves to the first value that's ready plus the next future.
//!     //
//!     // Note we can also use the `then` combinator which which is similar to
//!     // `and_then` above except that it receives the result of the
//!     // computation, not just the successful value.
//!     //
//!     // Again note that all the above calls to `and_then` and the below calls
//!     // to `map` and such require no allocations. We only ever allocate once
//!     // we hit the `.boxed()` call at the end here, which means we've built
//!     // up a relatively involved computation with only one box, and even that
//!     // was optional!
//!
//!     let data = data.map(Ok);
//!     let timeout = timeout(timeout_dur).map(Err);
//!
//!     let ret = data.select(timeout).then(|result| {
//!         match result {
//!             // One future succeeded, and it was the one which was
//!             // downloading data from the connection.
//!             Ok((Ok(data), _other_future)) => Ok(data),
//!
//!             // The timeout fired, and otherwise no error was found, so
//!             // we translate this to an error.
//!             Ok((Err(_timeout), _other_future)) => {
//!                 Err(io::Error::new(io::ErrorKind::Other, "timeout"))
//!             }
//!
//!             // A normal I/O error happened, so we pass that on through.
//!             Err((e, _other_future)) => Err(e),
//!         }
//!     });
//!     return Box::new(ret);
//!
//!     fn resolve(url: &str) -> IoFuture<SocketAddr> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn connect(hostname: &SocketAddr) -> IoFuture<TcpStream> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn download(stream: TcpStream) -> IoFuture<Vec<u8>> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn timeout(stream: Duration) -> IoFuture<()> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//! }
//! # fn main() {}
//! ```
//!
//! Some more information can also be found in the [README] for now, but
//! otherwise feel free to jump in to the docs below!
//!
//! [README]: https://github.com/alexcrichton/futures-rs#futures-rs

#![no_std]
#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/futures/0.1")]

#[macro_use]
#[cfg(feature = "use_std")]
extern crate std;

#[macro_use]
extern crate log;

macro_rules! if_std {
    ($($i:item)*) => ($(
        #[cfg(feature = "use_std")]
        $i
    )*)
}

#[macro_use]
mod poll;
pub use poll::{Poll, Async, AsyncSink, StartSend};

pub mod future;
pub use future::{Future, IntoFuture};

pub mod stream;
pub use stream::Stream;

pub mod sink;
pub use sink::Sink;

#[deprecated(since = "0.1.4", note = "import through the future module instead")]
pub use future::{done, empty, failed, finished, lazy};

#[doc(hidden)]
#[deprecated(since = "0.1.4", note = "import through the future module instead")]
pub use future::{
    Done, Empty, Failed, Finished, Lazy, AndThen, Flatten, FlattenStream, Fuse, IntoStream,
    Join, Join3, Join4, Join5, Map, MapErr, OrElse, Select, SelectNext, Then
};

if_std! {
    mod lock;
    mod task_impl;

    pub mod task;
    pub mod executor;
    pub mod sync;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::channel instead")]
    pub use sync::oneshot::channel as oneshot;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Receiver instead")]
    pub use sync::oneshot::Receiver as Oneshot;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Sender instead")]
    pub use sync::oneshot::Sender as Complete;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Canceled instead")]
    pub use sync::oneshot::Canceled;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "import through the future module instead")]
    pub use future::{BoxFuture, collect, select_all, select_ok};
}
<commit_msg>Also reexport SelectAllNext and SelectAll<commit_after>//! Zero-cost Futures in Rust
//!
//! This library is an implementation of futures in Rust which aims to provide
//! a robust implementation of handling asynchronous computations, ergonomic
//! composition and usage, and zero-cost abstractions over what would otherwise
//! be written by hand.
//!
//! Futures are a concept for an object which is a proxy for another value that
//! may not be ready yet. For example issuing an HTTP request may return a
//! future for the HTTP response, as it probably hasn't arrived yet. With an
//! object representing a value that will eventually be available, futures allow
//! for powerful composition of tasks through basic combinators that can perform
//! operations like chaining computations, changing the types of futures, or
//! waiting for two futures to complete at the same time.
//!
//! ## Installation
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! futures = "0.1"
//! ```
//!
//! ## Examples
//!
//! Let's take a look at a few examples of how futures might be used:
//!
//! ```
//! extern crate futures;
//!
//! use std::io;
//! use std::time::Duration;
//! use futures::{Future, Map};
//!
//! // A future is actually a trait implementation, so we can generically take a
//! // future of any integer and return back a future that will resolve to that
//! // value plus 10 more.
//! //
//! // Note here that like iterators, we're returning the `Map` combinator in
//! // the futures crate, not a boxed abstraction. This is a zero-cost
//! // construction of a future.
//! fn add_ten<F>(future: F) -> Map<F, fn(i32) -> i32>
//!     where F: Future<Item=i32>,
//! {
//!     fn add(a: i32) -> i32 { a + 10 }
//!     future.map(add)
//! }
//!
//! // Not only can we modify one future, but we can even compose them together!
//! // Here we have a function which takes two futures as input, and returns a
//! // future that will calculate the sum of their two values.
//! //
//! // Above we saw a direct return value of the `Map` combinator, but
//! // performance isn't always critical and sometimes it's more ergonomic to
//! // return a trait object like we do here. Note though that there's only one
//! // allocation here, not any for the intermediate futures.
//! fn add<'a, A, B>(a: A, b: B) -> Box<Future<Item=i32, Error=A::Error> + 'a>
//!     where A: Future<Item=i32> + 'a,
//!           B: Future<Item=i32, Error=A::Error> + 'a,
//! {
//!     Box::new(a.join(b).map(|(a, b)| a + b))
//! }
//!
//! // Futures also allow chaining computations together, starting another after
//! // the previous finishes. Here we wait for the first computation to finish,
//! // and then decide what to do depending on the result.
//! fn download_timeout(url: &str,
//!                     timeout_dur: Duration)
//!                     -> Box<Future<Item=Vec<u8>, Error=io::Error>> {
//!     use std::io;
//!     use std::net::{SocketAddr, TcpStream};
//!
//!     type IoFuture<T> = Box<Future<Item=T, Error=io::Error>>;
//!
//!     // First thing to do is we need to resolve our URL to an address. This
//!     // will likely perform a DNS lookup which may take some time.
//!     let addr = resolve(url);
//!
//!     // After we acquire the address, we next want to open up a TCP
//!     // connection.
//!     let tcp = addr.and_then(|addr| connect(&addr));
//!
//!     // After the TCP connection is established and ready to go, we're off to
//!     // the races!
//!     let data = tcp.and_then(|conn| download(conn));
//!
//!     // That all might take awhile, though, so let's not wait too long for it
//!     // to all come back. The `select` combinator here returns a future which
//!     // resolves to the first value that's ready plus the next future.
//!     //
//!     // Note we can also use the `then` combinator which which is similar to
//!     // `and_then` above except that it receives the result of the
//!     // computation, not just the successful value.
//!     //
//!     // Again note that all the above calls to `and_then` and the below calls
//!     // to `map` and such require no allocations. We only ever allocate once
//!     // we hit the `.boxed()` call at the end here, which means we've built
//!     // up a relatively involved computation with only one box, and even that
//!     // was optional!
//!
//!     let data = data.map(Ok);
//!     let timeout = timeout(timeout_dur).map(Err);
//!
//!     let ret = data.select(timeout).then(|result| {
//!         match result {
//!             // One future succeeded, and it was the one which was
//!             // downloading data from the connection.
//!             Ok((Ok(data), _other_future)) => Ok(data),
//!
//!             // The timeout fired, and otherwise no error was found, so
//!             // we translate this to an error.
//!             Ok((Err(_timeout), _other_future)) => {
//!                 Err(io::Error::new(io::ErrorKind::Other, "timeout"))
//!             }
//!
//!             // A normal I/O error happened, so we pass that on through.
//!             Err((e, _other_future)) => Err(e),
//!         }
//!     });
//!     return Box::new(ret);
//!
//!     fn resolve(url: &str) -> IoFuture<SocketAddr> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn connect(hostname: &SocketAddr) -> IoFuture<TcpStream> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn download(stream: TcpStream) -> IoFuture<Vec<u8>> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn timeout(stream: Duration) -> IoFuture<()> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//! }
//! # fn main() {}
//! ```
//!
//! Some more information can also be found in the [README] for now, but
//! otherwise feel free to jump in to the docs below!
//!
//! [README]: https://github.com/alexcrichton/futures-rs#futures-rs

#![no_std]
#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/futures/0.1")]

#[macro_use]
#[cfg(feature = "use_std")]
extern crate std;

#[macro_use]
extern crate log;

macro_rules! if_std {
    ($($i:item)*) => ($(
        #[cfg(feature = "use_std")]
        $i
    )*)
}

#[macro_use]
mod poll;
pub use poll::{Poll, Async, AsyncSink, StartSend};

pub mod future;
pub use future::{Future, IntoFuture};

pub mod stream;
pub use stream::Stream;

pub mod sink;
pub use sink::Sink;

#[deprecated(since = "0.1.4", note = "import through the future module instead")]
pub use future::{done, empty, failed, finished, lazy};

#[doc(hidden)]
#[deprecated(since = "0.1.4", note = "import through the future module instead")]
pub use future::{
    Done, Empty, Failed, Finished, Lazy, AndThen, Flatten, FlattenStream, Fuse, IntoStream,
    Join, Join3, Join4, Join5, Map, MapErr, OrElse, Select, SelectAll,
    SelectAllNext, SelectNext, Then
};

if_std! {
    mod lock;
    mod task_impl;

    pub mod task;
    pub mod executor;
    pub mod sync;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::channel instead")]
    pub use sync::oneshot::channel as oneshot;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Receiver instead")]
    pub use sync::oneshot::Receiver as Oneshot;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Sender instead")]
    pub use sync::oneshot::Sender as Complete;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "use sync::oneshot::Canceled instead")]
    pub use sync::oneshot::Canceled;

    #[doc(hidden)]
    #[deprecated(since = "0.1.4", note = "import through the future module instead")]
    pub use future::{BoxFuture, collect, select_all, select_ok};
}
<|endoftext|>


<commit_before>
pub fn puzzle(input: &str) -> u32 {
    let initial_world_state = WorldState {
        steps: 0,
        building: BuildingState {
            elevator_floor: 0,
            floors: [
                vec![
                    Component::Microchip(Element::Hydrogen),
                    Component::Microchip(Element::Lithium),
                ],
                vec![
                    Component::Generator(Element::Hydrogen),
                ],
                vec![
                    Component::Generator(Element::Lithium),
                ],
                vec![],
            ],
        }
    };
    let mut queue = vec![initial_world_state];
    while !queue.is_empty() {
        let world = queue.remove(0);
        if world.in_end_state() {
            return world.steps;
        }

        let mut valid_next_moves = world.next_moves();
        queue.append(&mut valid_next_moves);
    }

    panic!("Exhausted all possible moves without finding end condition!");
}

pub struct WorldState {
    steps: u32,
    building: BuildingState,
}

impl WorldState {
    pub fn in_end_state(&self) -> bool {
        self.building.in_end_state()
    }

    pub fn next_moves(&self) -> Vec<WorldState> {
        // TODO: actually determine valid next moves
        vec![]
    }
}

pub enum Component {
    Microchip(Element),
    Generator(Element),
}

pub enum Element {
    Hydrogen,
    Lithium,
}

pub struct BuildingState {
    elevator_floor: usize,
    floors: [Vec<Component>; 4],
}

impl BuildingState {
    pub fn in_end_state(&self) -> bool {
        self.floors[0].is_empty() &&
            self.floors[1].is_empty() &&
            self.floors[2].is_empty()
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn not_in_end_state() {
        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    vec![
                        Component::Microchip(Element::Hydrogen),
                        Component::Microchip(Element::Lithium),
                    ],
                    vec![
                        Component::Generator(Element::Hydrogen),
                    ],
                    vec![
                        Component::Generator(Element::Lithium),
                    ],
                    vec![],
                ],
            }
        };
        assert!( ! world_state.in_end_state() );
    }

    #[test]
    fn in_end_state() {
        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    vec![],
                    vec![],
                    vec![],
                    vec![
                        Component::Generator(Element::Hydrogen),
                        Component::Microchip(Element::Hydrogen),
                        Component::Microchip(Element::Lithium),
                        Component::Generator(Element::Lithium),
                    ],
                ],
            }
        };

        assert!(world_state.in_end_state());
    }
}
<commit_msg>Next world states are next buildings with one more step<commit_after>
pub fn puzzle(input: &str) -> u32 {
    let initial_world_state = WorldState {
        steps: 0,
        building: BuildingState {
            elevator_floor: 0,
            floors: [
                vec![
                    Component::Microchip(Element::Hydrogen),
                    Component::Microchip(Element::Lithium),
                ],
                vec![
                    Component::Generator(Element::Hydrogen),
                ],
                vec![
                    Component::Generator(Element::Lithium),
                ],
                vec![],
            ],
        }
    };
    let mut queue = vec![initial_world_state];
    while !queue.is_empty() {
        let world = queue.remove(0);
        if world.in_end_state() {
            return world.steps;
        }

        let mut valid_next_moves = world.next_moves();
        queue.append(&mut valid_next_moves);
    }

    panic!("Exhausted all possible moves without finding end condition!");
}

pub struct WorldState {
    steps: u32,
    building: BuildingState,
}

impl WorldState {
    pub fn in_end_state(&self) -> bool {
        self.building.in_end_state()
    }

    pub fn next_moves(&self) -> Vec<WorldState> {
        self.building.next_moves().into_iter().map(|b| {
            WorldState {
                steps: self.steps + 1,
                building: b,
            }
        }).collect()
    }
}

pub enum Component {
    Microchip(Element),
    Generator(Element),
}

pub enum Element {
    Hydrogen,
    Lithium,
}

pub struct BuildingState {
    elevator_floor: usize,
    floors: [Vec<Component>; 4],
}

impl BuildingState {
    pub fn in_end_state(&self) -> bool {
        self.floors[0].is_empty() &&
            self.floors[1].is_empty() &&
            self.floors[2].is_empty()
    }

    pub fn next_moves(&self) -> Vec<BuildingState> {
        // TODO: actually determine valid next moves
        vec![]
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn not_in_end_state() {
        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    vec![
                        Component::Microchip(Element::Hydrogen),
                        Component::Microchip(Element::Lithium),
                    ],
                    vec![
                        Component::Generator(Element::Hydrogen),
                    ],
                    vec![
                        Component::Generator(Element::Lithium),
                    ],
                    vec![],
                ],
            }
        };
        assert!( ! world_state.in_end_state() );
    }

    #[test]
    fn in_end_state() {
        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    vec![],
                    vec![],
                    vec![],
                    vec![
                        Component::Generator(Element::Hydrogen),
                        Component::Microchip(Element::Hydrogen),
                        Component::Microchip(Element::Lithium),
                        Component::Generator(Element::Lithium),
                    ],
                ],
            }
        };

        assert!(world_state.in_end_state());
    }
}
<|endoftext|>


<commit_before>//! Use the API Documentation below to learn about the various things you can do with this crate.
//!
//! **If this is your first time using Rust or using this crate, read the Guide on
//! [turtle.rs](http://turtle.rs) to learn how to start.**
//!
//! * The [`Turtle` struct](struct.Turtle.html) - lists of all the various drawing commands that the
//!   turtle supports
//! * The [`Drawing` struct](struct.Drawing.html) - allows you to manipulate the title, size,
//!   background and more of the drawing that you are creating
//! * The [`color` module](color/index.html) - describes the different ways to create colors and
//!   includes a list of the hundreds of predefined color names that you can use to easily set the
//!   pen, fill, and background color of your drawings
//!
//! Note: Call [`turtle::start()`](fn.start.html) if you do not create a turtle with
//! [`Turtle::new()`](struct.Turtle.html#method.new) right at the beginning of your program. Most
//! programs will never need to call this function as it is called for you in
//! [`Turtle::new()`](struct.Turtle.html#method.new).
//!
//! # Random Values
//!
//! See the [`rand` module](rand/index.html) for information about generating random colors, speeds,
//! angles, and more which can be used in your programs to produce some interesting results!
//!
//! # Event Handling
//!
//! The [`Event` enum](event/enum.Event.html) documentation provides information about how you can
//! create an event loop. This allows you to draw things in response to certain events like the
//! mouse moving, keys being pressed, and more.
//!
//! The `Turtle` struct contains a few convenience methods so you can do some common event-related
//! things without creating the entire event loop. For example, use
//! [`wait_for_click()`](struct.Turtle.html#method.wait_for_click) to wait for the user to click
//! anywhere on the screen before proceeding.
//! # Unstable features
//! Some parts of this library are unstable, such as maximizing and unmaximizing the window.
//! You can explicitly opt-in to using those features with the `unstable` feature like so:
//!
//! ```bash
//! $ cargo build --features "unstable"
//! ```
//!
//! If you want to use this from inside your own crate, you will need to add this to your Cargo.toml
//! ```toml
//! [dependencies]
//! turtle = { version = "...", features = ["unstable"] }
//! ```

// This warning usually signals an error and so it should be treated as such.
#![deny(unused_must_use)]

#![doc(html_logo_url = "https://raw.githubusercontent.com/sunjay/turtle/master/docs/assets/images/turtle-logo-512.png")]
#![cfg_attr(target_arch = "wasm32", crate_type = "cdylib")]

#[cfg(all(test, not(feature = "test")))]
compile_error!("Make sure you run tests with `cargo test --features test`");

mod ipc_protocol;
mod renderer_server;
mod renderer_client;
mod async_drawing;
mod async_turtle;
mod sync_runtime;
mod turtle;

mod turtle_window;

mod animation;
#[cfg(not(target_arch = "wasm32"))]
mod app;
mod drawing;
mod extensions;
#[cfg(not(target_arch = "wasm32"))]
mod messenger;
mod point;
mod query;
mod radians;
#[cfg(not(target_arch = "wasm32"))]
mod renderer2;
mod renderer_process;
#[cfg(not(target_arch = "wasm32"))]
mod server;
mod speed;
mod state2;
mod timer;

pub mod color;
#[cfg(not(target_arch = "wasm32"))]
pub mod event;
#[cfg(target_arch = "wasm32")]
mod event {
    use serde::{Serialize, Deserialize};
    #[derive(Debug, Clone, Serialize, Deserialize)]
    pub enum Event {}
}
pub mod rand;

pub use crate::color::Color;
pub use crate::async_drawing::Size;
pub use crate::drawing::Drawing;
pub use crate::event::Event;
pub use crate::point::Point;
#[cfg(target_arch = "wasm32")]
pub use renderer_process::{alloc, dealloc, dealloc_str};
pub use crate::speed::Speed;
pub use crate::async_turtle::{Angle, Distance};
pub use crate::turtle::Turtle;
use crate::renderer_server::ExportError;

#[cfg(not(target_arch = "wasm32"))]
pub use crate::server::start;
#[cfg(target_arch = "wasm32")]
pub fn start() {}
<commit_msg>Publically exposing renderer_server::start() instead of the old server::start()<commit_after>//! Use the API Documentation below to learn about the various things you can do with this crate.
//!
//! **If this is your first time using Rust or using this crate, read the Guide on
//! [turtle.rs](http://turtle.rs) to learn how to start.**
//!
//! * The [`Turtle` struct](struct.Turtle.html) - lists of all the various drawing commands that the
//!   turtle supports
//! * The [`Drawing` struct](struct.Drawing.html) - allows you to manipulate the title, size,
//!   background and more of the drawing that you are creating
//! * The [`color` module](color/index.html) - describes the different ways to create colors and
//!   includes a list of the hundreds of predefined color names that you can use to easily set the
//!   pen, fill, and background color of your drawings
//!
//! Note: Call [`turtle::start()`](fn.start.html) if you do not create a turtle with
//! [`Turtle::new()`](struct.Turtle.html#method.new) right at the beginning of your program. Most
//! programs will never need to call this function as it is called for you in
//! [`Turtle::new()`](struct.Turtle.html#method.new).
//!
//! # Random Values
//!
//! See the [`rand` module](rand/index.html) for information about generating random colors, speeds,
//! angles, and more which can be used in your programs to produce some interesting results!
//!
//! # Event Handling
//!
//! The [`Event` enum](event/enum.Event.html) documentation provides information about how you can
//! create an event loop. This allows you to draw things in response to certain events like the
//! mouse moving, keys being pressed, and more.
//!
//! The `Turtle` struct contains a few convenience methods so you can do some common event-related
//! things without creating the entire event loop. For example, use
//! [`wait_for_click()`](struct.Turtle.html#method.wait_for_click) to wait for the user to click
//! anywhere on the screen before proceeding.
//! # Unstable features
//! Some parts of this library are unstable, such as maximizing and unmaximizing the window.
//! You can explicitly opt-in to using those features with the `unstable` feature like so:
//!
//! ```bash
//! $ cargo build --features "unstable"
//! ```
//!
//! If you want to use this from inside your own crate, you will need to add this to your Cargo.toml
//! ```toml
//! [dependencies]
//! turtle = { version = "...", features = ["unstable"] }
//! ```

// This warning usually signals an error and so it should be treated as such.
#![deny(unused_must_use)]

#![doc(html_logo_url = "https://raw.githubusercontent.com/sunjay/turtle/master/docs/assets/images/turtle-logo-512.png")]
#![cfg_attr(target_arch = "wasm32", crate_type = "cdylib")]

#[cfg(all(test, not(feature = "test")))]
compile_error!("Make sure you run tests with `cargo test --features test`");

mod ipc_protocol;
mod renderer_server;
mod renderer_client;
mod async_drawing;
mod async_turtle;
mod sync_runtime;
mod turtle;

mod turtle_window;

mod animation;
#[cfg(not(target_arch = "wasm32"))]
mod app;
mod drawing;
mod extensions;
#[cfg(not(target_arch = "wasm32"))]
mod messenger;
mod point;
mod query;
mod radians;
#[cfg(not(target_arch = "wasm32"))]
mod renderer2;
mod renderer_process;
#[cfg(not(target_arch = "wasm32"))]
mod server;
mod speed;
mod state2;
mod timer;

pub mod color;
#[cfg(not(target_arch = "wasm32"))]
pub mod event;
#[cfg(target_arch = "wasm32")]
mod event {
    use serde::{Serialize, Deserialize};
    #[derive(Debug, Clone, Serialize, Deserialize)]
    pub enum Event {}
}
pub mod rand;

pub use crate::color::Color;
pub use crate::async_drawing::Size;
pub use crate::drawing::Drawing;
pub use crate::event::Event;
pub use crate::point::Point;
#[cfg(target_arch = "wasm32")]
pub use renderer_process::{alloc, dealloc, dealloc_str};
pub use crate::speed::Speed;
pub use crate::async_turtle::{Angle, Distance};
pub use crate::turtle::Turtle;
use crate::renderer_server::ExportError;

#[cfg(not(target_arch = "wasm32"))]
pub use crate::renderer_server::start;
#[cfg(target_arch = "wasm32")]
pub fn start() {}
<|endoftext|>