<commit_before>use ide_db::defs::{Definition, NameRefClass};
use syntax::{ast, AstNode, SyntaxKind, T};
use test_utils::mark;

use crate::{
    assist_context::{AssistContext, Assists},
    AssistId, AssistKind,
};

// Assist: add_type_ascription
//
// Adds `: _` before the assignment operator to prompt the user for a type
//
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x = make$0();
// }
// ```
// ->
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x: ${0:_} = make();
// }
// ```
pub(crate) fn add_type_ascription(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?;
    if let_stmt.colon_token().is_some() {
        mark::hit!(add_type_ascription_already_typed);
        return None
    }
    let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end();

    let ident = ctx.find_token_syntax_at_offset(SyntaxKind::IDENT).or_else(|| {
        let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?;
        if arg_list.args().count() > 0 {
            return None;
        }
        mark::hit!(add_type_ascription_after_call);
        arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT)
    })?;
    let next_token = ident.next_token()?;
    if next_token.kind() == T![::] {
        mark::hit!(add_type_ascription_turbofished);
        return None;
    }
    let name_ref = ast::NameRef::cast(ident.parent())?;
    let def = match NameRefClass::classify(&ctx.sema, &name_ref)? {
        NameRefClass::Definition(def) => def,
        NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None,
    };
    let fun = match def {
        Definition::ModuleDef(hir::ModuleDef::Function(it)) => it,
        _ => return None,
    };
    let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
    if generics.is_empty() {
        mark::hit!(add_type_ascription_non_generic);
        return None;
    }
    acc.add(
        AssistId("add_type_ascription", AssistKind::RefactorRewrite),
        "Add `: _` before assignment operator",
        ident.text_range(),
        |builder| match ctx.config.snippet_cap {
            Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"),
            None => builder.insert(type_pos, ": _"),
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;
    use test_utils::mark;

    #[test]
    fn add_type_ascription_function() {
        check_assist(
            add_type_ascription,
            r#"
fn make<T>() -> T {}
fn main() {
    let x = make$0();
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: ${0:_} = make();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_after_call() {
        mark::check!(add_type_ascription_after_call);
        check_assist(
            add_type_ascription,
            r#"
fn make<T>() -> T {}
fn main() {
    let x = make()$0;
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: ${0:_} = make();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_method() {
        check_assist(
            add_type_ascription,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    let x = S.make$0();
}
"#,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    let x: ${0:_} = S.make();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_turbofished() {
        mark::check!(add_type_ascription_turbofished);
        check_assist_not_applicable(
            add_type_ascription,
            r#"
fn make<T>() -> T {}
fn main() {
    let x = make$0::<()>();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_already_typed() {
        mark::check!(add_type_ascription_already_typed);
        check_assist_not_applicable(
            add_type_ascription,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: () = make$0();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_non_generic() {
        mark::check!(add_type_ascription_non_generic);
        check_assist_not_applicable(
            add_type_ascription,
            r#"
fn make() -> () {}
fn main() {
    let x = make$0();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_no_let() {
        check_assist_not_applicable(
            add_type_ascription,
            r#"
fn make<T>() -> T {}
fn main() {
    make$0();
}
"#,
        );
    }
}
<commit_msg>chore: fmt + docs<commit_after>use ide_db::defs::{Definition, NameRefClass};
use syntax::{ast, AstNode, SyntaxKind, T};
use test_utils::mark;

use crate::{
    assist_context::{AssistContext, Assists},
    AssistId, AssistKind,
};

// Assist: add_type_ascription
//
// Adds `: _` before the assignment operator to prompt the user for a type.
//
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x = make$0();
// }
// ```
// ->
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x: ${0:_} = make();
// }
// ```
pub(crate) fn add_type_ascription(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?;
    if let_stmt.colon_token().is_some() {
        mark::hit!(add_type_ascription_already_typed);
        return None;
    }
    let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end();

    let ident = ctx.find_token_syntax_at_offset(SyntaxKind::IDENT).or_else(|| {
        let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?;
        if arg_list.args().count() > 0 {
            return None;
        }
        mark::hit!(add_type_ascription_after_call);
        arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT)
    })?;
    let next_token = ident.next_token()?;
    if next_token.kind() == T![::] {
        mark::hit!(add_type_ascription_turbofished);
        return None;
    }
    let name_ref = ast::NameRef::cast(ident.parent())?;
    let def = match NameRefClass::classify(&ctx.sema, &name_ref)? {
        NameRefClass::Definition(def) => def,
        NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None,
    };
    let fun = match def {
        Definition::ModuleDef(hir::ModuleDef::Function(it)) => it,
        _ => return None,
    };
    let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
    if generics.is_empty() {
        mark::hit!(add_type_ascription_non_generic);
        return None;
    }
    acc.add(
        AssistId("add_type_ascription", AssistKind::RefactorRewrite),
        "Add `: _` before assignment operator",
        ident.text_range(),
        |builder| match ctx.config.snippet_cap {
            Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"),
            None => builder.insert(type_pos, ": _"),
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;
    use test_utils::mark;

    #[test]
    fn add_type_ascription_function() {
        check_assist(
            add_type_ascription,
            r#"
fn make<T>() -> T {}
fn main() {
    let x = make$0();
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: ${0:_} = make();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_after_call() {
        mark::check!(add_type_ascription_after_call);
        check_assist(
            add_type_ascription,
            r#"
fn make<T>() -> T {}
fn main() {
    let x = make()$0;
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: ${0:_} = make();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_method() {
        check_assist(
            add_type_ascription,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    let x = S.make$0();
}
"#,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    let x: ${0:_} = S.make();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_turbofished() {
        mark::check!(add_type_ascription_turbofished);
        check_assist_not_applicable(
            add_type_ascription,
            r#"
fn make<T>() -> T {}
fn main() {
    let x = make$0::<()>();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_already_typed() {
        mark::check!(add_type_ascription_already_typed);
        check_assist_not_applicable(
            add_type_ascription,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: () = make$0();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_non_generic() {
        mark::check!(add_type_ascription_non_generic);
        check_assist_not_applicable(
            add_type_ascription,
            r#"
fn make() -> () {}
fn main() {
    let x = make$0();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_no_let() {
        check_assist_not_applicable(
            add_type_ascription,
            r#"
fn make<T>() -> T {}
fn main() {
    make$0();
}
"#,
        );
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;

use runtime::{Class, Method, Object, Sel, self};
use {encode, Encode, EncodePtr};

/*
 The Sized bound on Message is unfortunate; ideally, objc objects would not be
 treated as Sized. However, rust won't allow casting a dynamically-sized type
 pointer to an Object pointer, because dynamically-sized types can have fat
 pointers (two words) instead of real pointers.
 */
/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message: Sized + EncodePtr { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

/// A trait for converting to a pointer to a type that may be sent Objective-C
/// messages.
pub trait ToMessage : Encode {
    type Target: Message;

    fn as_ptr(&self) -> *mut Self::Target;

    fn is_nil(&self) -> bool {
        self.as_ptr().is_null()
    }
}

impl<T> ToMessage for *const T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *mut T
    }
}

impl<T> ToMessage for *mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

impl<'a, T> ToMessage for &'a T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *const T as *mut T
    }
}

impl<'a, T> ToMessage for &'a mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

impl<'a, T> ToMessage for Option<&'a T> where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        match *self {
            None => ptr::null_mut(),
            Some(ref obj) => obj.as_ptr(),
        }
    }
}

impl<'a, T> ToMessage for Option<&'a mut T> where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        match *self {
            None => ptr::null_mut(),
            Some(ref obj) => obj.as_ptr(),
        }
    }
}

fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    unsafe {
        mem::transmute(runtime::objc_msgSend)
    }
}

pub trait MessageArguments {
    unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage;

    fn verify(&self, method: &Method) -> Result<(), String>;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t: Encode),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let obj_ptr = obj.as_ptr() as *mut Object;
                let ($($a,)*) = self;
                msg_send_fn(obj_ptr, sel $(, $a)*)
            }

            fn verify(&self, method: &Method) -> Result<(), String> {
                let types = [$(encode::<$t>()),*];
                verify_message_arguments(&types, method)
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

fn verify_message_arguments(types: &[&str], method: &Method) -> Result<(), String> {
    let count = 2 + types.len();
    let expected_count = method.arguments_count();
    if count != expected_count {
        return Err(format!("Method {:?} accepts {} arguments, but {} were given",
            method.name(), expected_count, count));
    }

    let expected_types = range(2, expected_count).map(|i| method.argument_type(i));
    for (&arg, expected) in types.iter().zip(expected_types) {
        let expected = match expected {
            Some(s) => s,
            None => return Err(format!("Method {:?} doesn't expect argument with type code {}",
                method.name(), arg)),
        };
        if arg != expected.as_slice() {
            return Err(format!("Method {:?} expected argument with type code {} but was given {}",
                method.name(), expected.as_slice(), arg));
        }
    }

    Ok(())
}

fn verify_message_signature<T, A, R>(obj: Option<&T>, sel: Sel, args: &A) ->
        Result<(), String> where T: Message, A: MessageArguments, R: Encode {
    let obj = match obj {
        Some(obj) => obj,
        None => return Err(format!("Messaging {:?} to nil", sel)),
    };
    let cls = unsafe {
        let obj = &*(obj as *const _ as *const Object);
        obj.class()
    };
    let method = match cls.instance_method(sel) {
        Some(method) => method,
        None => return Err(format!("Method {:?} not found on class {:?}",
            sel, cls)),
    };

    let ret = encode::<R>();
    let expected_ret = method.return_type();
    // Allow encoding "oneway void" (Vv) as "void" (v)
    if expected_ret.as_slice() != ret && !(expected_ret.as_slice() == "Vv" && ret == "v") {
        return Err(format!("Return type code {} does not match expected {} for method {:?} on class {:?}",
            ret, expected_ret.as_slice(), sel, cls));
    }

    // I don't think either of these can happen, but just to be safe...
    let accepts_self_arg = match method.argument_type(0) {
        Some(s) => s.as_slice() == "@",
        None => false,
    };
    if !accepts_self_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for self",
            sel, cls));
    }
    let accepts_cmd_arg = match method.argument_type(1) {
        Some(s) => s.as_slice() == ":",
        None => false,
    };
    if !accepts_cmd_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for the selector",
            sel, cls));
    }

    args.verify(method)
}

pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send(obj, sel)
}

pub unsafe fn send_message_verified<T, A, R>(obj: &T, sel: Sel, args: A) ->
        Result<R, String> where T: ToMessage, A: MessageArguments, R: Encode {
    let obj_ref = obj.as_ptr().as_ref();
    verify_message_signature::<_, _, R>(obj_ref, sel, &args).and_then(
        move |()| Ok(args.send(obj, sel)))
}
<commit_msg>Removed MessageArguments::verify for now.<commit_after>use std::mem;
use std::ptr;

use runtime::{Class, Method, Object, Sel, self};
use {encode, Encode, EncodePtr};

/*
 The Sized bound on Message is unfortunate; ideally, objc objects would not be
 treated as Sized. However, rust won't allow casting a dynamically-sized type
 pointer to an Object pointer, because dynamically-sized types can have fat
 pointers (two words) instead of real pointers.
 */
/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message: Sized + EncodePtr { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

/// A trait for converting to a pointer to a type that may be sent Objective-C
/// messages.
pub trait ToMessage : Encode {
    type Target: Message;

    fn as_ptr(&self) -> *mut Self::Target;

    fn is_nil(&self) -> bool {
        self.as_ptr().is_null()
    }
}

impl<T> ToMessage for *const T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *mut T
    }
}

impl<T> ToMessage for *mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

impl<'a, T> ToMessage for &'a T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self as *const T as *mut T
    }
}

impl<'a, T> ToMessage for &'a mut T where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        *self
    }
}

impl<'a, T> ToMessage for Option<&'a T> where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        match *self {
            None => ptr::null_mut(),
            Some(ref obj) => obj.as_ptr(),
        }
    }
}

impl<'a, T> ToMessage for Option<&'a mut T> where T: Message {
    type Target = T;

    fn as_ptr(&self) -> *mut T {
        match *self {
            None => ptr::null_mut(),
            Some(ref obj) => obj.as_ptr(),
        }
    }
}

fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    unsafe {
        mem::transmute(runtime::objc_msgSend)
    }
}

pub trait MessageArguments {
    unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let obj_ptr = obj.as_ptr() as *mut Object;
                let ($($a,)*) = self;
                msg_send_fn(obj_ptr, sel $(, $a)*)
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[allow(dead_code)]
fn verify_message_arguments(types: &[&str], method: &Method) -> Result<(), String> {
    let count = 2 + types.len();
    let expected_count = method.arguments_count();
    if count != expected_count {
        return Err(format!("Method {:?} accepts {} arguments, but {} were given",
            method.name(), expected_count, count));
    }

    let expected_types = range(2, expected_count).map(|i| method.argument_type(i));
    for (&arg, expected) in types.iter().zip(expected_types) {
        let expected = match expected {
            Some(s) => s,
            None => return Err(format!("Method {:?} doesn't expect argument with type code {}",
                method.name(), arg)),
        };
        if arg != expected.as_slice() {
            return Err(format!("Method {:?} expected argument with type code {} but was given {}",
                method.name(), expected.as_slice(), arg));
        }
    }

    Ok(())
}

fn verify_message_signature<T, A, R>(obj: Option<&T>, sel: Sel, _args: &A) ->
        Result<(), String> where T: Message, A: MessageArguments, R: Encode {
    let obj = match obj {
        Some(obj) => obj,
        None => return Err(format!("Messaging {:?} to nil", sel)),
    };
    let cls = unsafe {
        let obj = &*(obj as *const _ as *const Object);
        obj.class()
    };
    let method = match cls.instance_method(sel) {
        Some(method) => method,
        None => return Err(format!("Method {:?} not found on class {:?}",
            sel, cls)),
    };

    let ret = encode::<R>();
    let expected_ret = method.return_type();
    // Allow encoding "oneway void" (Vv) as "void" (v)
    if expected_ret.as_slice() != ret && !(expected_ret.as_slice() == "Vv" && ret == "v") {
        return Err(format!("Return type code {} does not match expected {} for method {:?} on class {:?}",
            ret, expected_ret.as_slice(), sel, cls));
    }

    // I don't think either of these can happen, but just to be safe...
    let accepts_self_arg = match method.argument_type(0) {
        Some(s) => s.as_slice() == "@",
        None => false,
    };
    if !accepts_self_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for self",
            sel, cls));
    }
    let accepts_cmd_arg = match method.argument_type(1) {
        Some(s) => s.as_slice() == ":",
        None => false,
    };
    if !accepts_cmd_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for the selector",
            sel, cls));
    }

    Ok(())
}

pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send(obj, sel)
}

pub unsafe fn send_message_verified<T, A, R>(obj: &T, sel: Sel, args: A) ->
        Result<R, String> where T: ToMessage, A: MessageArguments, R: Encode {
    let obj_ref = obj.as_ptr().as_ref();
    verify_message_signature::<_, _, R>(obj_ref, sel, &args).and_then(
        move |()| Ok(args.send(obj, sel)))
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

//! [![Latest Version](https://img.shields.io/crates/v/tarpc.svg)](https://crates.io/crates/tarpc)
//! [![Join the chat at https://gitter.im/tarpc/Lobby](https://badges.gitter.im/tarpc/Lobby.svg)](https://gitter.im/tarpc/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
//!
//! *Disclaimer*: This is not an official Google product.
//!
//! tarpc is an RPC framework for rust with a focus on ease of use. Defining a
//! service can be done in just a few lines of code, and most of the boilerplate of
//! writing a server is taken care of for you.
//!
//! [Documentation](https://docs.rs/crate/tarpc/)
//!
//! ## What is an RPC framework?
//! "RPC" stands for "Remote Procedure Call," a function call where the work of
//! producing the return value is being done somewhere else. When an rpc function is
//! invoked, behind the scenes the function contacts some other process somewhere
//! and asks them to evaluate the function instead. The original function then
//! returns the value produced by the other process.
//!
//! RPC frameworks are a fundamental building block of most microservices-oriented
//! architectures. Two well-known ones are [gRPC](http://www.grpc.io) and
//! [Cap'n Proto](https://capnproto.org/).
//!
//! tarpc differentiates itself from other RPC frameworks by defining the schema in code,
//! rather than in a separate language such as .proto. This means there's no separate compilation
//! process, and no context switching between different languages.
//!
//! Some other features of tarpc:
//! - Pluggable transport: any type impling `Stream<Item = Request> + Sink<Response>` can be
//!   used as a transport to connect the client and server.
//! - `Send + 'static` optional: if the transport doesn't require it, neither does tarpc!
//! - Cascading cancellation: dropping a request will send a cancellation message to the server.
//!   The server will cease any unfinished work on the request, subsequently cancelling any of its
//!   own requests, repeating for the entire chain of transitive dependencies.
//! - Configurable deadlines and deadline propagation: request deadlines default to 10s if
//!   unspecified. The server will automatically cease work when the deadline has passed. Any
//!   requests sent by the server that use the request context will propagate the request deadline.
//!   For example, if a server is handling a request with a 10s deadline, does 2s of work, then
//!   sends a request to another server, that server will see an 8s deadline.
//! - Serde serialization: enabling the `serde1` Cargo feature will make service requests and
//!   responses `Serialize + Deserialize`. It's entirely optional, though: in-memory transports can
//!   be used, as well, so the price of eerialization doesn't have to be paid when it's not needed.
//!
//! ## Usage
//! Add to your `Cargo.toml` dependencies:
//!
//! ```toml
//! tarpc = "0.18.0"
//! ```
//!
//! The `tarpc::service` attribute expands to a collection of items that form an rpc service.
//! These generated types make it easy and ergonomic to write servers with less boilerplate.
//! Simply implement the generated service trait, and you're off to the races!
//!
//! ## Example
//!
//! For this example, in addition to tarpc, also add two other dependencies to
//! your `Cargo.toml`:
//!
//! ```toml
//! futures-preview = "0.3.0-alpha.18"
//! tokio = "0.2.0-alpha.3"
//! ```
//!
//! In the following example, we use an in-process channel for communication between
//! client and server. In real code, you will likely communicate over the network.
//! For a more real-world example, see [example-service](example-service).
//!
//! First, let's set up the dependencies and service definition.
//!
//! ```rust
//! # extern crate futures;
//!
//! use futures::{
//!     future::{self, Ready},
//!     prelude::*,
//! };
//! use tarpc::{
//!     client, context,
//!     server::{self, Handler},
//! };
//! use std::io;
//!
//! // This is the service definition. It looks a lot like a trait definition.
//! // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! #[tarpc::service]
//! trait World {
//!     /// Returns a greeting for name.
//!     async fn hello(name: String) -> String;
//! }
//! ```
//!
//! This service definition generates a trait called `World`. Next we need to
//! implement it for our Server struct.
//!
//! ```rust
//! # extern crate futures;
//! # use futures::{
//! #     future::{self, Ready},
//! #     prelude::*,
//! # };
//! # use tarpc::{
//! #     client, context,
//! #     server::{self, Handler},
//! # };
//! # use std::io;
//! # // This is the service definition. It looks a lot like a trait definition.
//! # // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! # #[tarpc::service]
//! # trait World {
//! #     /// Returns a greeting for name.
//! #     async fn hello(name: String) -> String;
//! # }
//! // This is the type that implements the generated World trait. It is the business logic
//! // and is used to start the server.
//! #[derive(Clone)]
//! struct HelloServer;
//!
//! impl World for HelloServer {
//!     // Each defined rpc generates two items in the trait, a fn that serves the RPC, and
//!     // an associated type representing the future output by the fn.
//!
//!     type HelloFut = Ready<String>;
//!
//!     fn hello(self, _: context::Context, name: String) -> Self::HelloFut {
//!         future::ready(format!("Hello, {}!", name))
//!     }
//! }
//! ```
//!
//! Lastly let's write our `main` that will start the server. While this example uses an
//! [in-process
//! channel](https://docs.rs/tarpc/0.18.0/tarpc/transport/channel/struct.UnboundedChannel.html),
//! tarpc also ships
//! [bincode](https://docs.rs/tarpc-bincode-transport/0.7.0/tarpc_bincode_transport/)
//! and
//! [JSON](https://docs.rs/tarpc-json-transport/0.1.0/tarpc_json_transport)
//! tokio-net based TCP transports that are generic over all serializable types.
//!
//! ```rust
//! # extern crate futures;
//! # use futures::{
//! #     future::{self, Ready},
//! #     prelude::*,
//! # };
//! # use tarpc::{
//! #     client, context,
//! #     server::{self, Handler},
//! # };
//! # use std::io;
//! # // This is the service definition. It looks a lot like a trait definition.
//! # // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! # #[tarpc::service]
//! # trait World {
//! #     /// Returns a greeting for name.
//! #     async fn hello(name: String) -> String;
//! # }
//! # // This is the type that implements the generated World trait. It is the business logic
//! # // and is used to start the server.
//! # #[derive(Clone)]
//! # struct HelloServer;
//! # impl World for HelloServer {
//! #     // Each defined rpc generates two items in the trait, a fn that serves the RPC, and
//! #     // an associated type representing the future output by the fn.
//! #     type HelloFut = Ready<String>;
//! #     fn hello(self, _: context::Context, name: String) -> Self::HelloFut {
//! #         future::ready(format!("Hello, {}!", name))
//! #     }
//! # }
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
//!     let (client_transport, server_transport) = tarpc::transport::channel::unbounded();
//!
//!     let server = server::new(server::Config::default())
//!         // incoming() takes a stream of transports such as would be returned by
//!         // TcpListener::incoming (but a stream instead of an iterator).
//!         .incoming(stream::once(future::ready(server_transport)))
//!         .respond_with(HelloServer.serve());
//!
//!     tokio::spawn(server);
//!
//!     // WorldClient is generated by the macro. It has a constructor `new` that takes a config and
//!     // any Transport as input
//!     let mut client = WorldClient::new(client::Config::default(), client_transport).spawn()?;
//!
//!     // The client has an RPC method for each RPC defined in the annotated trait. It takes the same
//!     // args as defined, with the addition of a Context, which is always the first arg. The Context
//!     // specifies a deadline and trace information which can be helpful in debugging requests.
//!     let hello = client.hello(context::current(), "Stim".to_string()).await?;
//!
//!     println!("{}", hello);
//!
//!     Ok(())
//! }
//! ```
//!
//! ## Service Documentation
//!
//! Use `cargo doc` as you normally would to see the documentation created for all
//! items expanded by a `service!` invocation.

#![deny(missing_docs, missing_debug_implementations)]
pub use rpc::*;

/// The main macro that creates RPC services.
///
/// Rpc methods are specified, mirroring trait syntax:
///
/// ```
/// # fn main() {}
/// #[tarpc::service]
/// trait Service {
/// /// Say hello
/// async fn hello(name: String) -> String;
/// }
/// ```
///
/// Attributes can be attached to each rpc. These attributes
/// will then be attached to the generated service traits'
/// corresponding `fn`s, as well as to the client stubs' RPCs.
///
/// The following items are expanded in the enclosing module:
///
/// * `trait Service` -- defines the RPC service.
///   * `fn serve` -- turns a service impl into a request handler.
/// * `Client` -- a client stub with a fn for each RPC.
///   * `fn new_stub` -- creates a new Client stub.
pub use tarpc_plugins::service;
<commit_msg>Fix typo<commit_after>// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

//! [![Latest Version](https://img.shields.io/crates/v/tarpc.svg)](https://crates.io/crates/tarpc)
//! [![Join the chat at https://gitter.im/tarpc/Lobby](https://badges.gitter.im/tarpc/Lobby.svg)](https://gitter.im/tarpc/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
//!
//! *Disclaimer*: This is not an official Google product.
//!
//! tarpc is an RPC framework for rust with a focus on ease of use. Defining a
//! service can be done in just a few lines of code, and most of the boilerplate of
//! writing a server is taken care of for you.
//!
//! [Documentation](https://docs.rs/crate/tarpc/)
//!
//! ## What is an RPC framework?
//! "RPC" stands for "Remote Procedure Call," a function call where the work of
//! producing the return value is being done somewhere else. When an rpc function is
//! invoked, behind the scenes the function contacts some other process somewhere
//! and asks them to evaluate the function instead. The original function then
//! returns the value produced by the other process.
//!
//! RPC frameworks are a fundamental building block of most microservices-oriented
//! architectures. Two well-known ones are [gRPC](http://www.grpc.io) and
//! [Cap'n Proto](https://capnproto.org/).
//!
//! tarpc differentiates itself from other RPC frameworks by defining the schema in code,
//! rather than in a separate language such as .proto. This means there's no separate compilation
//! process, and no context switching between different languages.
//!
//! Some other features of tarpc:
//! - Pluggable transport: any type impling `Stream<Item = Request> + Sink<Response>` can be
//!   used as a transport to connect the client and server.
//! - `Send + 'static` optional: if the transport doesn't require it, neither does tarpc!
//! - Cascading cancellation: dropping a request will send a cancellation message to the server.
//!   The server will cease any unfinished work on the request, subsequently cancelling any of its
//!   own requests, repeating for the entire chain of transitive dependencies.
//! - Configurable deadlines and deadline propagation: request deadlines default to 10s if
//!   unspecified. The server will automatically cease work when the deadline has passed. Any
//!   requests sent by the server that use the request context will propagate the request deadline.
//!   For example, if a server is handling a request with a 10s deadline, does 2s of work, then
//!   sends a request to another server, that server will see an 8s deadline.
//! - Serde serialization: enabling the `serde1` Cargo feature will make service requests and
//!   responses `Serialize + Deserialize`. It's entirely optional, though: in-memory transports can
//!   be used, as well, so the price of serialization doesn't have to be paid when it's not needed.
//!
//! ## Usage
//! Add to your `Cargo.toml` dependencies:
//!
//! ```toml
//! tarpc = "0.18.0"
//! ```
//!
//! The `tarpc::service` attribute expands to a collection of items that form an rpc service.
//! These generated types make it easy and ergonomic to write servers with less boilerplate.
//! Simply implement the generated service trait, and you're off to the races!
//!
//! ## Example
//!
//! For this example, in addition to tarpc, also add two other dependencies to
//! your `Cargo.toml`:
//!
//! ```toml
//! futures-preview = "0.3.0-alpha.18"
//! tokio = "0.2.0-alpha.3"
//! ```
//!
//! In the following example, we use an in-process channel for communication between
//! client and server. In real code, you will likely communicate over the network.
//! For a more real-world example, see [example-service](example-service).
//!
//! First, let's set up the dependencies and service definition.
//!
//! ```rust
//! # extern crate futures;
//!
//! use futures::{
//!     future::{self, Ready},
//!     prelude::*,
//! };
//! use tarpc::{
//!     client, context,
//!     server::{self, Handler},
//! };
//! use std::io;
//!
//! // This is the service definition. It looks a lot like a trait definition.
//! // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! #[tarpc::service]
//! trait World {
//!     /// Returns a greeting for name.
//!     async fn hello(name: String) -> String;
//! }
//! ```
//!
//! This service definition generates a trait called `World`. Next we need to
//! implement it for our Server struct.
//!
//! ```rust
//! # extern crate futures;
//! # use futures::{
//! #     future::{self, Ready},
//! #     prelude::*,
//! # };
//! # use tarpc::{
//! #     client, context,
//! #     server::{self, Handler},
//! # };
//! # use std::io;
//! # // This is the service definition. It looks a lot like a trait definition.
//! # // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! # #[tarpc::service]
//! # trait World {
//! #     /// Returns a greeting for name.
//! #     async fn hello(name: String) -> String;
//! # }
//! // This is the type that implements the generated World trait. It is the business logic
//! // and is used to start the server.
//! #[derive(Clone)]
//! struct HelloServer;
//!
//! impl World for HelloServer {
//!     // Each defined rpc generates two items in the trait, a fn that serves the RPC, and
//!     // an associated type representing the future output by the fn.
//!
//!     type HelloFut = Ready<String>;
//!
//!     fn hello(self, _: context::Context, name: String) -> Self::HelloFut {
//!         future::ready(format!("Hello, {}!", name))
//!     }
//! }
//! ```
//!
//! Lastly let's write our `main` that will start the server. While this example uses an
//! [in-process
//! channel](https://docs.rs/tarpc/0.18.0/tarpc/transport/channel/struct.UnboundedChannel.html),
//! tarpc also ships
//! [bincode](https://docs.rs/tarpc-bincode-transport/0.7.0/tarpc_bincode_transport/)
//! and
//! [JSON](https://docs.rs/tarpc-json-transport/0.1.0/tarpc_json_transport)
//! tokio-net based TCP transports that are generic over all serializable types.
//!
//! ```rust
//! # extern crate futures;
//! # use futures::{
//! #     future::{self, Ready},
//! #     prelude::*,
//! # };
//! # use tarpc::{
//! #     client, context,
//! #     server::{self, Handler},
//! # };
//! # use std::io;
//! # // This is the service definition. It looks a lot like a trait definition.
//! # // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! # #[tarpc::service]
//! # trait World {
//! #     /// Returns a greeting for name.
//! #     async fn hello(name: String) -> String;
//! # }
//! # // This is the type that implements the generated World trait. It is the business logic
//! # // and is used to start the server.
//! # #[derive(Clone)]
//! # struct HelloServer;
//! # impl World for HelloServer {
//! #     // Each defined rpc generates two items in the trait, a fn that serves the RPC, and
//! #     // an associated type representing the future output by the fn.
//! #     type HelloFut = Ready<String>;
//! #     fn hello(self, _: context::Context, name: String) -> Self::HelloFut {
//! #         future::ready(format!("Hello, {}!", name))
//! #     }
//! # }
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
//!     let (client_transport, server_transport) = tarpc::transport::channel::unbounded();
//!
//!     let server = server::new(server::Config::default())
//!         // incoming() takes a stream of transports such as would be returned by
//!         // TcpListener::incoming (but a stream instead of an iterator).
//!         .incoming(stream::once(future::ready(server_transport)))
//!         .respond_with(HelloServer.serve());
//!
//!     tokio::spawn(server);
//!
//!     // WorldClient is generated by the macro. It has a constructor `new` that takes a config and
//!     // any Transport as input
//!     let mut client = WorldClient::new(client::Config::default(), client_transport).spawn()?;
//!
//!     // The client has an RPC method for each RPC defined in the annotated trait. It takes the same
//!     // args as defined, with the addition of a Context, which is always the first arg. The Context
//!     // specifies a deadline and trace information which can be helpful in debugging requests.
//!     let hello = client.hello(context::current(), "Stim".to_string()).await?;
//!
//!     println!("{}", hello);
//!
//!     Ok(())
//! }
//! ```
//!
//! ## Service Documentation
//!
//! Use `cargo doc` as you normally would to see the documentation created for all
//! items expanded by a `service!` invocation.

#![deny(missing_docs, missing_debug_implementations)]
pub use rpc::*;

/// The main macro that creates RPC services.
///
/// Rpc methods are specified, mirroring trait syntax:
///
/// ```
/// # fn main() {}
/// #[tarpc::service]
/// trait Service {
/// /// Say hello
/// async fn hello(name: String) -> String;
/// }
/// ```
///
/// Attributes can be attached to each rpc. These attributes
/// will then be attached to the generated service traits'
/// corresponding `fn`s, as well as to the client stubs' RPCs.
///
/// The following items are expanded in the enclosing module:
///
/// * `trait Service` -- defines the RPC service.
///   * `fn serve` -- turns a service impl into a request handler.
/// * `Client` -- a client stub with a fn for each RPC.
///   * `fn new_stub` -- creates a new Client stub.
pub use tarpc_plugins::service;
<|endoftext|>


<commit_before>use glium::backend::Context;
use Camera;
use render::ToArr;
use base::math::*;
use base::world::{HexPillar, PropType};
use world::chunk::Vertex;
use std::rc::Rc;
use glium;

/// Graphical representation of a 'base::Plant'
pub struct PlantView {
    /// contains the vertices for vertex shader
    vertices: glium::VertexBuffer<Vertex>,
    /// program links vertex and fragment shader together
    program: glium::Program,
    plants_pos: Vec<Point2f>,
    /// Context for IndexBuffer
    con: Rc<Context>,
}

impl PlantView {
    /// Creates the graphical representation of given plant
    /// at the given plant offset
    pub fn from_dummy_plant<F>(hex_vec: &[HexPillar],
      pillars_pos: Vec<Point2f>, facade: &F) -> Self
        where F: glium::backend::Facade
    {
        // get height and width for the plant from given Prop
        let (width, height) = match hex_vec[0].props()[0].prop() {
            &PropType::Plant(p) => (p.stem_width, p.height),
        }

        // Context for the draw method
        // to fill the IndexBuffer
        let c = facade.get_context().clone();

        let buffer = vec![Vertex {
                              position: [0.0, 1.0 * width, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 1.0 * width, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 1.0 * width,
                                1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 1.0 * width, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 0.0, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 0.0, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 0.0, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 0.0, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          }];

        let vbuf = glium::VertexBuffer::new(facade, &buffer).unwrap();
        let prog = glium::Program::from_source(facade,
                                               include_str!("plant_dummy.vert"),
                                               include_str!("plant_dummy.frag"),
                                               None)
            .unwrap();

        PlantView {
            vertices: vbuf,
            program: prog,
            plants_pos: pillars_pos,
            con: c,
        }
    }

    pub fn draw<S>(&self, surface: &mut S, camera: &Camera)
        where S: glium::Surface
    {
        // initialise the IndexBuffer
        let index: [u32; 30] = [1, 0, 2, 2, 0, 3, 2, 3, 4, 4, 3, 5, 4, 5,
                                6, 4, 6, 7, 7, 6, 0, 7,
                                0, 1, 1, 4, 7, 4, 1, 2];
        let ibuf = glium::index::IndexBuffer::new(&self.con,
                      glium::index::PrimitiveType::TrianglesList,
                      &index).unwrap();

        for plant_pos in &self.plants_pos {
            let uniforms = uniform! {
                offset: [plant_pos.x, plant_pos.y],
                proj_matrix: camera.proj_matrix().to_arr(),
                view_matrix: camera.view_matrix().to_arr(),
            };

            surface.draw(&self.vertices,
                      &ibuf,
                      &self.program,
                      &uniforms,
                      &Default::default())
                .unwrap();
        }

    }
}
<commit_msg>More improvements<commit_after>use glium::backend::Context;
use Camera;
use render::ToArr;
use base::math::*;
use base::world::{HexPillar, PropType};
use world::chunk::Vertex;
use std::rc::Rc;
use glium;

/// Graphical representation of a 'base::Plant'
pub struct PlantView {
    /// contains the vertices for vertex shader
    vertices: glium::VertexBuffer<Vertex>,
    /// program links vertex and fragment shader together
    program: glium::Program,
    plants_pos: Vec<Point2f>,
    /// Context for IndexBuffer
    con: Rc<Context>,
}

impl PlantView {
    /// Creates the graphical representation of given plant
    /// at the given plant offset
    pub fn from_dummy_plant<F>(hex_vec: &[HexPillar],
      pillars_pos: Vec<Point2f>, facade: &F) -> Self
        where F: glium::backend::Facade
    {
        // get height and width for the plant from given Prop
        let (width, height) = match hex_vec[0].props()[0].prop {
            PropType::Plant(p) => (p.stem_width, p.height),
        };

        // Context for the draw method
        // to fill the IndexBuffer
        let c = facade.get_context().clone();

        let buffer = vec![Vertex {
                              position: [0.0, 1.0 * width, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 1.0 * width, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 1.0 * width,
                                1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 1.0 * width, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 0.0, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 0.0, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 0.0, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 0.0, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          }];

        let vbuf = glium::VertexBuffer::new(facade, &buffer).unwrap();
        let prog = glium::Program::from_source(facade,
                                               include_str!("plant_dummy.vert"),
                                               include_str!("plant_dummy.frag"),
                                               None)
            .unwrap();

        PlantView {
            vertices: vbuf,
            program: prog,
            plants_pos: pillars_pos,
            con: c,
        }
    }

    pub fn draw<S>(&self, surface: &mut S, camera: &Camera)
        where S: glium::Surface
    {
        // initialise the IndexBuffer
        let index: [u32; 30] = [1, 0, 2, 2, 0, 3, 2, 3, 4, 4, 3, 5, 4, 5,
                                6, 4, 6, 7, 7, 6, 0, 7,
                                0, 1, 1, 4, 7, 4, 1, 2];
        let ibuf = glium::index::IndexBuffer::new(&self.con,
                      glium::index::PrimitiveType::TrianglesList,
                      &index).unwrap();

        for plant_pos in &self.plants_pos {
            let uniforms = uniform! {
                offset: [plant_pos.x, plant_pos.y],
                proj_matrix: camera.proj_matrix().to_arr(),
                view_matrix: camera.view_matrix().to_arr(),
            };

            surface.draw(&self.vertices,
                      &ibuf,
                      &self.program,
                      &uniforms,
                      &Default::default())
                .unwrap();
        }

    }
}
<|endoftext|>


<commit_before>//! An information element is a portion of a SBD message.
//!
//! Information elements come after the SBD header. They come in many types, including more
//! header-type information and the actual data payload.

use std::io::Read;

use Result;

/// An information element, or IE.
///
/// These are the building blocks of a SBD message. There are several types, generally divided into
/// MO and MT IE's. This general structure just holds the basic IE data, when then can be converted
/// into a specific type of IE.
#[derive(Debug)]
pub struct InformationElement;

impl InformationElement {

    /// Reads an information element from something that implements `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::{Seek, SeekFrom};
    /// use std::fs::File;
    /// use sbd::information_element::InformationElement;
    /// let mut file = File::open("data/0-mo.sbd").unwrap();
    /// file.seek(SeekFrom::Start(3));
    /// let readable = file.take(28);
    /// InformationElement::read_from(readable).unwrap();
    /// ```
    pub fn read_from<R: Read>(readable: R) -> Result<InformationElement> {
        Ok(InformationElement)
    }

    /// Returns the length of the information element.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::io::{Seek, SeekFrom};
    /// # use std::fs::File;
    /// # use sbd::information_element::InformationElement;
    /// # let mut file = File::open("data/0-mo.sbd").unwrap();
    /// # file.seek(SeekFrom::Start(3));
    /// # let readable = file.take(28);
    /// let information_element = InformationElement::read_from(readable).unwrap();
    /// assert_eq!(28, information_element.len());
    /// ```
    pub fn len(&self) -> u16 {
        1
    }
}

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

    use std::io::{Read, Seek, SeekFrom};
    use std::fs::File;

    #[test]
    fn read_from() {
        let mut file = File::open("data/0-mo.sbd").unwrap();
        file.seek(SeekFrom::Start(3));
        let readable = file.take(28);
        InformationElement::read_from(readable).unwrap();
    }

    #[test]
    fn len() {
        let mut file = File::open("data/0-mo.sbd").unwrap();
        file.seek(SeekFrom::Start(3));
        let readable = file.take(28);
        let ie = InformationElement::read_from(readable).unwrap();
        assert_eq!(28, ie.len());
    }
}
<commit_msg>Dummy in IE's len()<commit_after>//! An information element is a portion of a SBD message.
//!
//! Information elements come after the SBD header. They come in many types, including more
//! header-type information and the actual data payload.

use std::io::Read;

use Result;

/// An information element, or IE.
///
/// These are the building blocks of a SBD message. There are several types, generally divided into
/// MO and MT IE's. This general structure just holds the basic IE data, when then can be converted
/// into a specific type of IE.
#[derive(Debug)]
pub struct InformationElement;

impl InformationElement {

    /// Reads an information element from something that implements `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::{Seek, SeekFrom};
    /// use std::fs::File;
    /// use sbd::information_element::InformationElement;
    /// let mut file = File::open("data/0-mo.sbd").unwrap();
    /// file.seek(SeekFrom::Start(3));
    /// let readable = file.take(28);
    /// InformationElement::read_from(readable).unwrap();
    /// ```
    pub fn read_from<R: Read>(readable: R) -> Result<InformationElement> {
        Ok(InformationElement)
    }

    /// Returns the length of the information element.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::io::{Seek, SeekFrom};
    /// # use std::fs::File;
    /// # use sbd::information_element::InformationElement;
    /// # let mut file = File::open("data/0-mo.sbd").unwrap();
    /// # file.seek(SeekFrom::Start(3));
    /// # let readable = file.take(28);
    /// let information_element = InformationElement::read_from(readable).unwrap();
    /// assert_eq!(28, information_element.len());
    /// ```
    pub fn len(&self) -> u16 {
        28
    }
}

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

    use std::io::{Read, Seek, SeekFrom};
    use std::fs::File;

    #[test]
    fn read_from() {
        let mut file = File::open("data/0-mo.sbd").unwrap();
        file.seek(SeekFrom::Start(3));
        let readable = file.take(28);
        InformationElement::read_from(readable).unwrap();
    }

    #[test]
    fn len() {
        let mut file = File::open("data/0-mo.sbd").unwrap();
        file.seek(SeekFrom::Start(3));
        let readable = file.take(28);
        let ie = InformationElement::read_from(readable).unwrap();
        assert_eq!(28, ie.len());
    }
}
<|endoftext|>


<commit_before><commit_msg>Don't include Module for older llvms<commit_after><|endoftext|>


<commit_before>use time::{at_utc, Tm, Timespec};
use json::{FromJsonnable, ToJsonnable};
use serde::de::{Error, Type};
use serde_json::value::Value;
use serde_json::error::Error as JsonError;
use serde_json::builder::ObjectBuilder;

impl FromJsonnable for Tm {
	// Deserialize via Timespec
	fn from_json(json: Value) -> Result<Self, JsonError> {
		match json {
			Value::Object(map) => {
				let sec =
					match map.get("sec") {
						Some(sec) =>
							match sec {
								&Value::I64(sec) => sec,
								&Value::U64(sec) => sec as i64,  // The types get weird here
								_ => return Err(JsonError::type_mismatch(Type::I64)),
							},
						None => return Err(JsonError::missing_field("Missing \"sec\"")),
					};
				let nsec =
					match map.get("nsec") {
						Some(nsec) =>
							match nsec {
								&Value::I64(nsec) => nsec as i32,
								&Value::U64(nsec) => nsec as i32,
								_ => return Err(JsonError::type_mismatch(Type::I32)),
							},
						None => return Err(JsonError::missing_field("Missing \"nsec\"")),
					};

				Ok(at_utc(Timespec::new(sec, nsec)))
			},
			_ => Err(JsonError::type_mismatch(Type::Struct)),
		}
	}
}

impl ToJsonnable for Tm {
	// Serialize via Timespec
	fn to_json(&self) -> Value {
		let spec = self.to_timespec();
		ObjectBuilder::new().insert("sec", &spec.sec)
		                    .insert("nsec", &spec.nsec)
		                    .unwrap()
	}
}

impl<T: FromJsonnable> FromJsonnable for Vec<T> {
	fn from_json(json: Value) -> Result<Self, JsonError> {
		match json {
			Value::Array(arr) => {
				let mut elems: Vec<T> = Vec::with_capacity(arr.len());
				for elem in arr {
					match T::from_json(elem) {
						Ok(elem) => elems.push(elem),
						Err(e) => return Err(e),
					}
				}
				Ok(elems)
			},
			_ => Err(JsonError::type_mismatch(Type::Seq)),
		}
	}
}

impl<T: ToJsonnable> ToJsonnable for Vec<T> {
	fn to_json(&self) -> Value {
		Value::Array(self.iter().map(|ref elem| elem.to_json()).collect())
	}
}
<commit_msg>Add (untested) {From,To}Jsonnable impls for primitive types<commit_after>use time::{at_utc, Tm, Timespec};
use json::{FromJsonnable, ToJsonnable};
use serde::de::{Error, Type};
use serde_json::value::Value;
use serde_json::error::Error as JsonError;
use serde_json::builder::ObjectBuilder;

impl FromJsonnable for Tm {
	// Deserialize via Timespec
	fn from_json(json: Value) -> Result<Self, JsonError> {
		match json {
			Value::Object(map) => {
				let sec =
					match map.get("sec") {
						Some(sec) =>
							match sec {
								&Value::I64(sec) => sec,
								&Value::U64(sec) => sec as i64,  // The types get weird here
								_ => return Err(JsonError::type_mismatch(Type::I64)),
							},
						None => return Err(JsonError::missing_field("Missing \"sec\"")),
					};
				let nsec =
					match map.get("nsec") {
						Some(nsec) =>
							match nsec {
								&Value::I64(nsec) => nsec as i32,
								&Value::U64(nsec) => nsec as i32,
								_ => return Err(JsonError::type_mismatch(Type::I32)),
							},
						None => return Err(JsonError::missing_field("Missing \"nsec\"")),
					};

				Ok(at_utc(Timespec::new(sec, nsec)))
			},
			_ => Err(JsonError::type_mismatch(Type::Struct)),
		}
	}
}

impl ToJsonnable for Tm {
	// Serialize via Timespec
	fn to_json(&self) -> Value {
		let spec = self.to_timespec();
		ObjectBuilder::new().insert("sec", &spec.sec)
		                    .insert("nsec", &spec.nsec)
		                    .unwrap()
	}
}

impl<T: FromJsonnable> FromJsonnable for Vec<T> {
	fn from_json(json: Value) -> Result<Self, JsonError> {
		match json {
			Value::Array(arr) => {
				let mut elems: Vec<T> = Vec::with_capacity(arr.len());
				for elem in arr {
					match T::from_json(elem) {
						Ok(elem) => elems.push(elem),
						Err(e) => return Err(e),
					}
				}
				Ok(elems)
			},
			_ => Err(JsonError::type_mismatch(Type::Seq)),
		}
	}
}

impl<T: ToJsonnable> ToJsonnable for Vec<T> {
	fn to_json(&self) -> Value {
		Value::Array(self.iter().map(|ref elem| elem.to_json()).collect())
	}
}

macro_rules! primitive_to_json {
	($t:ty, $v:ident, $d:ty) => {
		impl ToJsonnable for $t {
			fn to_json(&self) -> Value {
				Value::$v(self.clone() as $d)
			}
		}
	};
}

macro_rules! primitive_from_json {
	($t:ty, $v:ident) => {
		impl FromJsonnable for $t {
			fn from_json(json: Value) -> Result<Self, JsonError> {
				match json {
					Value::$v(value) => Ok(value as $t),
					_ => Err(JsonError::type_mismatch(Type::$v)),
				}
			}
		}
	};
}

primitive_to_json!(i8,  I64, i64);
primitive_to_json!(i16, I64, i64);
primitive_to_json!(i32, I64, i64);
primitive_to_json!(i64, I64, i64);

primitive_to_json!(u8,  U64, u64);
primitive_to_json!(u16, U64, u64);
primitive_to_json!(u32, U64, u64);
primitive_to_json!(u64, U64, u64);

primitive_to_json!(f32, F64, f64);
primitive_to_json!(f64, F64, f64);

primitive_from_json!(i8,  I64);
primitive_from_json!(i16, I64);
primitive_from_json!(i32, I64);
primitive_from_json!(i64, I64);

primitive_from_json!(u8,  U64);
primitive_from_json!(u16, U64);
primitive_from_json!(u32, U64);
primitive_from_json!(u64, U64);

primitive_from_json!(f32, F64);
primitive_from_json!(f64, F64);
<|endoftext|>


<commit_before>#![allow(unstable)]
#![feature(box_syntax)]

use std::io::{BufferedWriter, File};
use std::ops::{Add, Sub, Mul};
use std::num::Float;

#[derive(Show)]
#[derive(Copy, Clone)]
struct Vector {
    x: f64,
    y: f64,
    z: f64
}

#[derive(Show, Copy, Clone)]
struct Ray {
    o: Vector,
    d: Vector
}

#[derive(Show, Clone)]
enum Reflection {
    DIFF,
    SPEC,
    REFR
}

#[derive(Show, Clone)]
struct Sphere {
    radius: f64,
    position: Vector,
    emission: Vector,
    color: Vector,
    reflection: Reflection
}

trait Intersect {
    fn intersect(self, r: Ray) -> f64;
}

impl Intersect for Sphere {
    fn intersect(self, r: Ray) -> f64 {
        // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0
        let eps = 1e-4;
        let op = &self.position - &r.o;
        let b = op.dot(&r.d);
        let mut det = b * b - op.dot(&op) + self.radius * self.radius;

        if det < 0.0 {
            return 0.0;
        } else {
            det = det.sqrt();
        }

        if (b - det) > eps {
            return b-det;
        }

        if (b + det) > eps {
            return b+det;
        }

        return 0.0;
    }
}

impl<'a> Add for &'a Vector {
    type Output = Vector;

    fn add(self, other: &'a Vector) -> Vector {
        Vector {x: self.x + other.x, y: self.y + other.y, z: self.z + other.z}
    }
}

impl<'a> Sub for &'a Vector {
    type Output = Vector;

    fn sub(self, other: &'a Vector) -> Vector {
        Vector {x: self.x - other.x, y: self.y - other.y, z: self.z - other.z}
    }
}

impl<'a> Mul for &'a Vector {
    type Output = Vector;

    fn mul(self, other: &'a Vector) -> Vector {
        Vector {x: self.x * other.x, y: self.y * other.y, z: self.z * other.z}
    }
}

trait VectorOps {
    fn smul(self, rhs: f64) -> Vector;
    fn norm(self) -> Vector;
    fn cross(self, rhs: Vector) -> Vector;
    fn dot(&self, rhs: &Vector) -> f64;
}

impl VectorOps for Vector {

    fn smul(self, other: f64) -> Vector {
        Vector {x: self.x * other, y: self.y * other, z: self.z * other}
    }

    fn norm(self) -> Vector {
        let normalize = 1.0 / (self.x * self.x + self.y * self.y + self.z * self.z).sqrt() ;
        self.smul( normalize )
    }

    fn cross(self, b: Vector) -> Vector {
        Vector{x: self.y * b.z - self.z * b.y, y: self.z * b.x - self.x * b.z, z: self.x * b.y - self.y * b.x}
    }

    fn dot(&self, other: &Vector) -> f64 {
        (*self).x * (*other).x + (*self).y * (*other).y + (*self).z * (*other).z
    }
}

fn clamp(x: f64) -> f64
{
    if x < 0.0 {
        return 0.0;
    }
    if x > 1.0 {
        return 1.0;
    }

    x
}

fn to_int(x: f64) -> i64
{
    (clamp(x).powf(1.0 / 2.2) * 255.0 + 0.5) as i64
}

fn intersect(r: Ray, t: &mut f64, id: &mut usize) -> bool
{
    let inf = 10e20f64;
    *t = inf;
    for (i, sphere) in SPHERES.iter().enumerate() {
        let d: f64 = sphere.clone().intersect(r.clone());
        if d != 0.0 && d < *t {
            *t = d;
            *id = i;
        }

    }
    return *t < inf;

}

static SPHERES: [Sphere; 2] = [
    Sphere{ radius: 150f64,  position: Vector{ x:212.0, y: 384.0, z: -1000f64},  emission: Vector{x: 0.0, y: 0.0, z: 0.0},  color: Vector{x: 0.25, y: 0.25, z: 0.75},   reflection: Reflection::DIFF},
    Sphere{ radius: 150f64,  position: Vector{ x:590.0, y: 884.0, z: -1000f64},  emission: Vector{x: 0.0, y: 0.0, z: 0.0},  color: Vector{x: 0.25, y: 0.25, z: 0.75},   reflection: Reflection::DIFF},
];

const WIDTH: usize = 1024;
const HEIGHT: usize = 768;

fn main() {
    println!("Raytracing...");

    let mut output = box [[Vector{x: 0.0, y: 0.0, z: 0.0}; WIDTH]; HEIGHT];
    for i in range(0, HEIGHT) {
        for j in range(0, WIDTH) {
            //println!("i, j = ({}, {})", i, j);
            let origin: Vector = Vector { x: i as f64, y: j as f64, z: 0.0};
            let direction: Vector = Vector { x: 0.0, y: 0.0, z: -1.0};
            let ray: Ray = Ray{o: origin, d: direction};

            let mut t: f64 = 0.0;
            let mut id: usize = 0;
            if intersect(ray, &mut t, &mut id) {
                output[i][j].x = 0.9;
                output[i][j].y = 0.9;
                output[i][j].z = 0.9;
            }
            else {
                output[i][j].x = 0.5;
                output[i][j].y = 0.5;
                output[i][j].z = 0.5;
            }
        }
    }

    println!("Writing Image...");
    let file = File::create(&Path::new("image.ppm"));
    let mut writer = BufferedWriter::new(file);

    writer.write(format!("P3\n{} {}\n{}\n", WIDTH, HEIGHT, 255).as_bytes()).ok();
    for i in range(0, HEIGHT) {
        for j in range(0, WIDTH) {
            writer.write(format!("{} {} {} ", to_int(output[i][j].x), to_int(output[i][j].y), to_int(output[i][j].z)).as_bytes()).ok();
        }
    }
}<commit_msg>Remove unnecessary code.<commit_after>#![allow(unstable)]
#![feature(box_syntax)]

use std::io::{BufferedWriter, File};
use std::ops::{Add, Sub, Mul};
use std::num::Float;

#[derive(Show)]
#[derive(Copy, Clone)]
struct Vector {
    x: f64,
    y: f64,
    z: f64
}

#[derive(Show, Copy, Clone)]
struct Ray {
    o: Vector,
    d: Vector
}

#[derive(Show, Clone)]
struct Sphere {
    radius: f64,
    position: Vector,
    color: Vector,
}

trait Intersect {
    fn intersect(self, r: Ray) -> f64;
}

impl Intersect for Sphere {
    fn intersect(self, r: Ray) -> f64 {
        // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0
        let eps = 1e-4;
        let op = &self.position - &r.o;
        let b = op.dot(&r.d);
        let mut det = b * b - op.dot(&op) + self.radius * self.radius;

        if det < 0.0 {
            return 0.0;
        } else {
            det = det.sqrt();
        }

        if (b - det) > eps {
            return b-det;
        }

        if (b + det) > eps {
            return b+det;
        }

        return 0.0;
    }
}

impl<'a> Add for &'a Vector {
    type Output = Vector;

    fn add(self, other: &'a Vector) -> Vector {
        Vector {x: self.x + other.x, y: self.y + other.y, z: self.z + other.z}
    }
}

impl<'a> Sub for &'a Vector {
    type Output = Vector;

    fn sub(self, other: &'a Vector) -> Vector {
        Vector {x: self.x - other.x, y: self.y - other.y, z: self.z - other.z}
    }
}

impl<'a> Mul for &'a Vector {
    type Output = Vector;

    fn mul(self, other: &'a Vector) -> Vector {
        Vector {x: self.x * other.x, y: self.y * other.y, z: self.z * other.z}
    }
}

trait VectorOps {
    fn smul(self, rhs: f64) -> Vector;
    fn norm(self) -> Vector;
    fn cross(self, rhs: Vector) -> Vector;
    fn dot(&self, rhs: &Vector) -> f64;
}

impl VectorOps for Vector {

    fn smul(self, other: f64) -> Vector {
        Vector {x: self.x * other, y: self.y * other, z: self.z * other}
    }

    fn norm(self) -> Vector {
        let normalize = 1.0 / (self.x * self.x + self.y * self.y + self.z * self.z).sqrt() ;
        self.smul( normalize )
    }

    fn cross(self, b: Vector) -> Vector {
        Vector{x: self.y * b.z - self.z * b.y, y: self.z * b.x - self.x * b.z, z: self.x * b.y - self.y * b.x}
    }

    fn dot(&self, other: &Vector) -> f64 {
        (*self).x * (*other).x + (*self).y * (*other).y + (*self).z * (*other).z
    }
}

fn clamp(x: f64) -> f64
{
    if x < 0.0 {
        return 0.0;
    }
    if x > 1.0 {
        return 1.0;
    }

    x
}

fn to_int(x: f64) -> i64
{
    (clamp(x).powf(1.0 / 2.2) * 255.0 + 0.5) as i64
}

fn intersect(r: Ray, t: &mut f64, id: &mut usize) -> bool
{
    let inf = 10e20f64;
    *t = inf;
    for (i, sphere) in SPHERES.iter().enumerate() {
        let d: f64 = sphere.clone().intersect(r.clone());
        if d != 0.0 && d < *t {
            *t = d;
            *id = i;
        }

    }
    return *t < inf;

}

static SPHERES: [Sphere; 2] = [
    Sphere{ radius: 150f64,  position: Vector{ x:212.0, y: 384.0, z: -1000f64}, color: Vector{x: 0.25, y: 0.25, z: 0.75} },
    Sphere{ radius: 150f64,  position: Vector{ x:590.0, y: 884.0, z: -1000f64}, color: Vector{x: 0.25, y: 0.50, z: 0.75} },
];

const WIDTH: usize = 1024;
const HEIGHT: usize = 768;

fn main() {
    println!("Raytracing...");

    let mut output = box [[Vector{x: 0.0, y: 0.0, z: 0.0}; WIDTH]; HEIGHT];
    for i in range(0, HEIGHT) {
        for j in range(0, WIDTH) {
            //println!("i, j = ({}, {})", i, j);
            let origin: Vector = Vector { x: i as f64, y: j as f64, z: 0.0};
            let direction: Vector = Vector { x: 0.0, y: 0.0, z: -1.0};
            let ray: Ray = Ray{o: origin, d: direction};

            let mut t: f64 = 0.0;
            let mut id: usize = 0;
            if intersect(ray, &mut t, &mut id) {
                output[i][j] = SPHERES[id].color;
            }
            else {
                output[i][j].x = 0.5;
                output[i][j].y = 0.5;
                output[i][j].z = 0.5;
            }
        }
    }

    println!("Writing Image...");
    let file = File::create(&Path::new("image.ppm"));
    let mut writer = BufferedWriter::new(file);

    writer.write(format!("P3\n{} {}\n{}\n", WIDTH, HEIGHT, 255).as_bytes()).ok();
    for i in range(0, HEIGHT) {
        for j in range(0, WIDTH) {
            writer.write(format!("{} {} {} ", to_int(output[i][j].x), to_int(output[i][j].y), to_int(output[i][j].z)).as_bytes()).ok();
        }
    }
}<|endoftext|>


<commit_before>use super::Encoder;
use super::s::{EncoderPreset, EncodeResult};
use crate::io::IoProxy;
use crate::ffi::BitmapBgra;
use imageflow_types::PixelFormat;
use imageflow_types::PixelBuffer;
use crate::{Context, Result, ErrorKind, FlowError};
use std::result::Result as StdResult;
use crate::io::IoProxyRef;
use std::slice;
use std::rc::Rc;
use std::cell::RefCell;
use std::os::raw::c_int;
use mozjpeg;
use evalchroma;
use evalchroma::PixelSize;
use crate::codecs::lode;
use std::io::Write;

#[derive(Copy, Clone)]
enum Defaults {
    MozJPEG,
    LibJPEGv6,
}

pub struct MozjpegEncoder {
    io: IoProxy,
    quality: Option<u8>,
    progressive: Option<bool>,
    optimize_coding: Option<bool>,
    defaults: Defaults,
}

impl MozjpegEncoder {
    // Quality is in range 0-100
    pub(crate) fn create(c: &Context, quality: Option<u8>, progressive: Option<bool>, io: IoProxy) -> Result<Self> {
        if !c.enabled_codecs.encoders.contains(&crate::codecs::NamedEncoders::MozJpegEncoder){
            return Err(nerror!(ErrorKind::CodecDisabledError, "The MozJpeg encoder has been disabled"));
        }
        Ok(MozjpegEncoder {
            io, quality, progressive,
            optimize_coding: Some(true),
            defaults: Defaults::MozJPEG,
        })
    }

    pub(crate) fn create_classic(c: &Context, quality: Option<u8>, progressive: Option<bool>, optimize_coding: Option<bool>, io: IoProxy) -> Result<Self> {
        Ok(MozjpegEncoder {
            io, quality, progressive,
            optimize_coding,
            defaults: Defaults::LibJPEGv6,
        })
    }
}

impl Encoder for MozjpegEncoder {
    fn write_frame(&mut self, c: &Context, _preset: &EncoderPreset, frame: &mut BitmapBgra, _decoder_io_ids: &[i32]) -> Result<EncodeResult> {
        let in_color_space = match frame.fmt {
            PixelFormat::Bgra32 => mozjpeg::ColorSpace::JCS_EXT_BGRA,
            PixelFormat::Bgr32 => mozjpeg::ColorSpace::JCS_EXT_BGRX,
            PixelFormat::Bgr24 => mozjpeg::ColorSpace::JCS_EXT_BGR,
            PixelFormat::Gray8 => mozjpeg::ColorSpace::JCS_GRAYSCALE,
        };
        let mut cinfo = mozjpeg::Compress::new(in_color_space);
        cinfo.set_size(frame.width(), frame.height());
        match self.defaults {
            Defaults::MozJPEG => {},
            Defaults::LibJPEGv6 => {
                cinfo.set_fastest_defaults();
            },
        }
        if let Some(q) = self.quality {
            cinfo.set_quality(q.into());
        }
        if let Some(p) = self.progressive {
            if p {
                cinfo.set_progressive_mode();
            }
        }
        if let Some(o) = self.optimize_coding {
            cinfo.set_optimize_coding(o);
        }

        let chroma_quality = self.quality.unwrap_or(75) as f32; // Lower values allow blurrier color
        let pixels_buffer = unsafe {frame.pixels_buffer()}.ok_or(nerror!(ErrorKind::BitmapPointerNull))?;
        let max_sampling = PixelSize{cb:(2,2), cr:(2,2)}; // Set to 1 to force higher res
        let res = match pixels_buffer {
            PixelBuffer::Bgra32(buf) => evalchroma::adjust_sampling(buf, max_sampling, chroma_quality),
            PixelBuffer::Bgr32(buf) => evalchroma::adjust_sampling(buf, max_sampling, chroma_quality),
            PixelBuffer::Bgr24(buf) => evalchroma::adjust_sampling(buf, max_sampling, chroma_quality),
            PixelBuffer::Gray8(buf) => evalchroma::adjust_sampling(buf, max_sampling, chroma_quality),
        };

        // Translate chroma pixel size into JPEG's channel-relative samples per pixel
        let max_sampling_h = res.subsampling.cb.0.max(res.subsampling.cr.0);
        let max_sampling_v = res.subsampling.cb.1.max(res.subsampling.cr.1);
        let px_sizes = &[(1,1), res.subsampling.cb, res.subsampling.cr];
        for (c, &(h, v)) in cinfo.components_mut().iter_mut().zip(px_sizes) {
            c.h_samp_factor = (max_sampling_h / h).into();
            c.v_samp_factor = (max_sampling_v / v).into();
        }

        cinfo.set_mem_dest();
        cinfo.start_compress();
        let pixels_slice = unsafe {frame.pixels_slice()}.ok_or(nerror!(ErrorKind::BitmapPointerNull))?;
        if frame.width() == frame.stride() {
            cinfo.write_scanlines(pixels_slice);
        } else {
            let width_bytes = frame.width() * frame.fmt.bytes();
            for row in pixels_slice.chunks(frame.stride()) {
                cinfo.write_scanlines(&row[0..width_bytes]);
            }
        }
        cinfo.finish_compress();
        let data = cinfo.data_as_mut_slice()
            .map_err(|_| nerror!(ErrorKind::MozjpegEncodingError, "Internal error"))?;
        self.io.write_all(data).map_err(|e| FlowError::from_encoder(e))?;

        Ok(EncodeResult {
            w: frame.w as i32,
            h: frame.h as i32,
            io_id: self.io.io_id(),
            bytes: ::imageflow_types::ResultBytes::Elsewhere,
            preferred_extension: "jpg".to_owned(),
            preferred_mime_type: "image/jpeg".to_owned(),
        })
    }

    fn get_io(&self) -> Result<IoProxyRef> {
        Ok(IoProxyRef::Borrow(&self.io))
    }
}
<commit_msg>Clamp jpeg quality 0..100<commit_after>use super::Encoder;
use super::s::{EncoderPreset, EncodeResult};
use crate::io::IoProxy;
use crate::ffi::BitmapBgra;
use imageflow_types::PixelFormat;
use imageflow_types::PixelBuffer;
use crate::{Context, Result, ErrorKind, FlowError};
use std::result::Result as StdResult;
use crate::io::IoProxyRef;
use std::slice;
use std::rc::Rc;
use std::cell::RefCell;
use std::os::raw::c_int;
use mozjpeg;
use evalchroma;
use evalchroma::PixelSize;
use crate::codecs::lode;
use std::io::Write;

#[derive(Copy, Clone)]
enum Defaults {
    MozJPEG,
    LibJPEGv6,
}

pub struct MozjpegEncoder {
    io: IoProxy,
    quality: Option<u8>,
    progressive: Option<bool>,
    optimize_coding: Option<bool>,
    defaults: Defaults,
}

impl MozjpegEncoder {
    // Quality is in range 0-100
    pub(crate) fn create(c: &Context, quality: Option<u8>, progressive: Option<bool>, io: IoProxy) -> Result<Self> {
        if !c.enabled_codecs.encoders.contains(&crate::codecs::NamedEncoders::MozJpegEncoder){
            return Err(nerror!(ErrorKind::CodecDisabledError, "The MozJpeg encoder has been disabled"));
        }
        Ok(MozjpegEncoder {
            io, quality, progressive,
            optimize_coding: Some(true),
            defaults: Defaults::MozJPEG,
        })
    }

    pub(crate) fn create_classic(c: &Context, quality: Option<u8>, progressive: Option<bool>, optimize_coding: Option<bool>, io: IoProxy) -> Result<Self> {
        Ok(MozjpegEncoder {
            io, quality, progressive,
            optimize_coding,
            defaults: Defaults::LibJPEGv6,
        })
    }
}

impl Encoder for MozjpegEncoder {
    fn write_frame(&mut self, c: &Context, _preset: &EncoderPreset, frame: &mut BitmapBgra, _decoder_io_ids: &[i32]) -> Result<EncodeResult> {
        let in_color_space = match frame.fmt {
            PixelFormat::Bgra32 => mozjpeg::ColorSpace::JCS_EXT_BGRA,
            PixelFormat::Bgr32 => mozjpeg::ColorSpace::JCS_EXT_BGRX,
            PixelFormat::Bgr24 => mozjpeg::ColorSpace::JCS_EXT_BGR,
            PixelFormat::Gray8 => mozjpeg::ColorSpace::JCS_GRAYSCALE,
        };
        let mut cinfo = mozjpeg::Compress::new(in_color_space);
        cinfo.set_size(frame.width(), frame.height());
        match self.defaults {
            Defaults::MozJPEG => {},
            Defaults::LibJPEGv6 => {
                cinfo.set_fastest_defaults();
            },
        }
        if let Some(q) = self.quality {
            cinfo.set_quality(u8::min(100,q).into());
        }
        if let Some(p) = self.progressive {
            if p {
                cinfo.set_progressive_mode();
            }
        }
        if let Some(o) = self.optimize_coding {
            cinfo.set_optimize_coding(o);
        }

        let chroma_quality = self.quality.unwrap_or(75) as f32; // Lower values allow blurrier color
        let pixels_buffer = unsafe {frame.pixels_buffer()}.ok_or(nerror!(ErrorKind::BitmapPointerNull))?;
        let max_sampling = PixelSize{cb:(2,2), cr:(2,2)}; // Set to 1 to force higher res
        let res = match pixels_buffer {
            PixelBuffer::Bgra32(buf) => evalchroma::adjust_sampling(buf, max_sampling, chroma_quality),
            PixelBuffer::Bgr32(buf) => evalchroma::adjust_sampling(buf, max_sampling, chroma_quality),
            PixelBuffer::Bgr24(buf) => evalchroma::adjust_sampling(buf, max_sampling, chroma_quality),
            PixelBuffer::Gray8(buf) => evalchroma::adjust_sampling(buf, max_sampling, chroma_quality),
        };

        // Translate chroma pixel size into JPEG's channel-relative samples per pixel
        let max_sampling_h = res.subsampling.cb.0.max(res.subsampling.cr.0);
        let max_sampling_v = res.subsampling.cb.1.max(res.subsampling.cr.1);
        let px_sizes = &[(1,1), res.subsampling.cb, res.subsampling.cr];
        for (c, &(h, v)) in cinfo.components_mut().iter_mut().zip(px_sizes) {
            c.h_samp_factor = (max_sampling_h / h).into();
            c.v_samp_factor = (max_sampling_v / v).into();
        }

        cinfo.set_mem_dest();
        cinfo.start_compress();
        let pixels_slice = unsafe {frame.pixels_slice()}.ok_or(nerror!(ErrorKind::BitmapPointerNull))?;
        if frame.width() == frame.stride() {
            cinfo.write_scanlines(pixels_slice);
        } else {
            let width_bytes = frame.width() * frame.fmt.bytes();
            for row in pixels_slice.chunks(frame.stride()) {
                cinfo.write_scanlines(&row[0..width_bytes]);
            }
        }
        cinfo.finish_compress();
        let data = cinfo.data_as_mut_slice()
            .map_err(|_| nerror!(ErrorKind::MozjpegEncodingError, "Internal error"))?;
        self.io.write_all(data).map_err(|e| FlowError::from_encoder(e))?;

        Ok(EncodeResult {
            w: frame.w as i32,
            h: frame.h as i32,
            io_id: self.io.io_id(),
            bytes: ::imageflow_types::ResultBytes::Elsewhere,
            preferred_extension: "jpg".to_owned(),
            preferred_mime_type: "image/jpeg".to_owned(),
        })
    }

    fn get_io(&self) -> Result<IoProxyRef> {
        Ok(IoProxyRef::Borrow(&self.io))
    }
}
<|endoftext|>