<commit_before>#![crate_id="CSVProvider#0.1-pre"]
#![crate_type="dylib"]

// why doesn't "lib" work?

// rustc 0.11.0-pre (b47f2226a25654c5b781d27a91f2fa5274b3a347 2014-06-28 14:31:37 +0000)

#![feature(globs, macro_rules, quote, managed_boxes, plugin_registrar)]

#![allow(unused_imports)]
#![allow(unused_variable)]

extern crate syntax;
extern crate rustc;

use syntax::ast::{
   Name,
   TokenTree,
   Expr,
   ExprLit,
   ExprVec,
   LitStr,
   DUMMY_NODE_ID,
   MutImmutable
};
use syntax::codemap::Span;
use syntax::ext::base::{
   SyntaxExtension,
   BasicMacroExpander,
   ExtCtxt,
   MacResult,
   MacPat,
   MacItem,
   DummyResult,
   MacExpr,
   NormalTT
};
use std::gc::Gc;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF};

use std::io;
use std::io::fs;
use std::os;
use std::str;
use std::io::Process;
use syntax::ast;
use syntax::ast::Name;

use syntax::util::small_vector::SmallVector;

use std::collections::HashMap;
use std::gc::{Gc, GC};

use rustc::plugin::Registry;

#[plugin_registrar]
pub fn macro_registrar(reg: &mut Registry) {
   reg.register_macro("ProvideCSV_labels", provide_csv_given_labels);
}

#[deriving(Clone)]
struct Entry {
   str: InternedString,
   expr: Gc<Expr>
}

// see https://github.com/sfackler/syntax-ext-talk/blob/gh-pages/simple-ext/lib.rs
fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
   let mut parser = parse::new_parser_from_tts(
       cx.parse_sess(),
       cx.cfg(),
       tts.iter()
          .map(|x| (*x).clone())
          .collect()
   );

   let mut entries: Vec<Entry> = Vec::new();

   let mut error = false;
   while parser.token != EOF {
      let entry = parser.parse_expr();

      let entry_str = match entry.node {
         ExprLit(lit) => {
            match lit.node {
               LitStr(ref s, _) => s.clone(),
               _ => {
                  cx.span_err(entry.span, "expected string literal (1)");
                  error = true;
                  InternedString::new("")
               }
            }
         }
         _ => {
                cx.span_err(entry.span, "expected string literal (2)");
                error = true;
                InternedString::new("")
         }
      };

      entries.push(Entry { str: entry_str, expr: entry });

      if !parser.eat(&COMMA) && parser.token != EOF {
         cx.span_err(parser.span, "expected `,`");
         return None;
      }
    }

   if error {
      return None;
   }

   Some(entries)
}

/// A convenience type for macros that return a single item.
pub struct MacItems {
   items: Vec<Gc<ast::Item>>
}

impl MacItems {
   pub fn new(items: Vec<Gc<ast::Item>>) -> Box<MacResult> {
      box MacItems { items: items } as Box<MacResult>
   }
}
impl MacResult for MacItems {
   fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
      Some(SmallVector::many(self.items.clone()))
   }
}

fn provide_csv_given_labels(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
   let mut entries = match parse_entries(cx, tts) {
      Some(entries) => entries,
      None => return DummyResult::expr(sp),
   };

   let raw_name   : Entry = entries.shift().expect("should be given a type name");
   let raw_path   : Entry = entries.shift().expect("should be given a CSV file path");
   let raw_labels : Entry = entries.shift().expect("should be given column labels");

   let name   : InternedString = raw_name.str;
   let path   : InternedString = raw_path.str;
   let labels : InternedString = raw_labels.str;

   println!("provide_csv_given_labels: name:   {}", name);
   println!("provide_csv_given_labels: path:   {}", path);
   println!("provide_csv_given_labels: labels: {}", labels);

   // PENDING
   // read the CSV and try to get the type of data in it
   // create a type with
   //  * this name,
   //  * these labeled columns,
   //  * discovered type of data
   //  * a constructor which reads the whole file

/* OLD
   let banana = "YAY! BANANA!";
   return MacExpr::new(quote_expr!(cx, {let x: $banana = 44}));
 */

   fn define_my_csv(cx0: &mut ExtCtxt) -> Option<Gc<syntax::ast::Item>> {
      let item1: Option<Gc<syntax::ast::Item>>  = quote_item!(cx0,
         pub struct MyCSV {
            pub data: Vec<(String)>,
         }
      );
      return item1;
   }

   let item1 = define_my_csv(cx);  // Why is this necessary?

   // PENDING FIXME:
   let magic : TokenTree = token::str_to_ident(name.to_string());

   let item2: Option<Gc<syntax::ast::Item>>  = quote_item!(cx,
      impl $magic {
         pub fn new() -> MyCSV {
            println!("HMMMMMM.");
            return MyCSV {
               data: (vec!["zero".to_string(), "one".to_string(), "two".to_string()]),
            };
         }
      }
   );

   let items = vec![item1.expect("Should be able to construct MyCSV."),
                    item2.expect("Should be able to construct MyCSV.")];
   return MacItems::new(items);
}

<commit_msg>cleanup<commit_after>#![crate_id="CSVProvider#0.1-pre"]
#![crate_type="dylib"]

// why doesn't "lib" work?

// rustc 0.11.0-pre (b47f2226a25654c5b781d27a91f2fa5274b3a347 2014-06-28 14:31:37 +0000)

#![feature(globs, macro_rules, quote, managed_boxes, plugin_registrar)]

#![allow(unused_imports)]
#![allow(unused_variable)]

extern crate syntax;
extern crate rustc;

use syntax::ast::{
   Name,
   TokenTree,
   Expr,
   ExprLit,
   ExprVec,
   LitStr,
   DUMMY_NODE_ID,
   MutImmutable
};
use syntax::codemap::Span;
use syntax::ext::base::{
   SyntaxExtension,
   BasicMacroExpander,
   ExtCtxt,
   MacResult,
   MacPat,
   MacItem,
   DummyResult,
   MacExpr,
   NormalTT
};
use std::gc::Gc;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF};

use std::io;
use std::io::fs;
use std::os;
use std::str;
use std::io::Process;
use syntax::ast;
use syntax::ast::Name;

use syntax::util::small_vector::SmallVector;

use std::collections::HashMap;
use std::gc::{Gc, GC};

use rustc::plugin::Registry;

#[plugin_registrar]
pub fn macro_registrar(reg: &mut Registry) {
   reg.register_macro("ProvideCSV_labels", provide_csv_given_labels);
}

#[deriving(Clone)]
struct Entry {
   str: InternedString,
   expr: Gc<Expr>
}

// see https://github.com/sfackler/syntax-ext-talk/blob/gh-pages/simple-ext/lib.rs
fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
   let mut parser = parse::new_parser_from_tts(
       cx.parse_sess(),
       cx.cfg(),
       tts.iter()
          .map(|x| (*x).clone())
          .collect()
   );

   let mut entries: Vec<Entry> = Vec::new();

   let mut error = false;
   while parser.token != EOF {
      let entry = parser.parse_expr();

      let entry_str = match entry.node {
         ExprLit(lit) => {
            match lit.node {
               LitStr(ref s, _) => s.clone(),
               _ => {
                  cx.span_err(entry.span, "expected string literal (1)");
                  error = true;
                  InternedString::new("")
               }
            }
         }
         _ => {
                cx.span_err(entry.span, "expected string literal (2)");
                error = true;
                InternedString::new("")
         }
      };

      entries.push(Entry { str: entry_str, expr: entry });

      if !parser.eat(&COMMA) && parser.token != EOF {
         cx.span_err(parser.span, "expected `,`");
         return None;
      }
    }

   if error {
      return None;
   }

   Some(entries)
}

/// A convenience type for macros that return a single item.
pub struct MacItems {
   items: Vec<Gc<ast::Item>>
}

impl MacItems {
   pub fn new(items: Vec<Gc<ast::Item>>) -> Box<MacResult> {
      box MacItems { items: items } as Box<MacResult>
   }
}
impl MacResult for MacItems {
   fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
      Some(SmallVector::many(self.items.clone()))
   }
}

fn provide_csv_given_labels(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
   let mut entries = match parse_entries(cx, tts) {
      Some(entries) => entries,
      None => return DummyResult::expr(sp),
   };

   let raw_name   : Entry = entries.shift().expect("should be given a type name");
   let raw_path   : Entry = entries.shift().expect("should be given a CSV file path");
   let raw_labels : Entry = entries.shift().expect("should be given column labels");

   let name   : InternedString = raw_name.str;
   let path   : InternedString = raw_path.str;
   let labels : InternedString = raw_labels.str;

   println!("provide_csv_given_labels: name:   {}", name);
   println!("provide_csv_given_labels: path:   {}", path);
   println!("provide_csv_given_labels: labels: {}", labels);

   // PENDING
   // read the CSV and try to get the type of data in it
   // create a type with
   //  * this name,
   //  * these labeled columns,
   //  * discovered type of data
   //  * a constructor which reads the whole file

/* OLD
   let banana = "YAY! BANANA!";
   return MacExpr::new(quote_expr!(cx, {let x: $banana = 44}));
 */

   // (2) PENDING FIXME
   // given a macro argument "Xyz" we want to use it everywhere without the quotes ;)
   let MyCSV : TokenTree = token::str_to_ident(name.to_string());

   fn define_my_csv(cx0: &mut ExtCtxt) -> Option<Gc<syntax::ast::Item>> {
      let item1: Option<Gc<syntax::ast::Item>>  = quote_item!(cx0,
         pub struct /* FIXME: $ */ MyCSV {
            pub data: Vec<(String)>,
         }
      );
      return item1;
   }

   let item1 = define_my_csv(cx);  // (1) Why is this necessary?

   let item2: Option<Gc<syntax::ast::Item>>  = quote_item!(cx,
      impl $MyCSV {
         pub fn new() -> $MyCSV {
            println!("HMMMMMM.");
            return $MyCSV {
               data: (vec!["zero".to_string(), "one".to_string(), "two".to_string()]),
            };
         }
      }
   );

   let items = vec![item1.expect("Should be able to construct MyCSV."),
                    item2.expect("Should be able to construct MyCSV.")];
   return MacItems::new(items);
}

<|endoftext|>


<commit_before>extern crate byteorder;
pub mod rom_loader;
pub mod memory;
pub mod cpu;

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();

    if args.len() < 2 {
      println!("Usage: main FILE");
      return;
    }

    println!("Loading {}", args[1]);
    let cpu: cpu::CpuState;

    match rom_loader::load_ines("roms/nestest.nes") {
    //match load_ines(args[1]) {
      Ok(_) => (),
      Err(err) => println!("Error: {:?}", err),
    }
}

<commit_msg>for now we don't need to take args input<commit_after>extern crate byteorder;
pub mod rom_loader;
pub mod memory;
pub mod cpu;

use std::env;

fn main() {
    //let args: Vec<String> = env::args().collect();

    //if args.len() < 2 {
      //println!("Usage: main FILE");
      //return;
    //}

    //println!("Loading {}", args[1]);
    let cpu: cpu::CpuState;

    match rom_loader::load_ines("roms/nestest.nes") {
    //match load_ines(args[1]) {
      Ok(_) => (),
      Err(err) => println!("Error: {:?}", err),
    }
}

<|endoftext|>


<commit_before>extern crate clap;
extern crate dent;

use clap::{App, Arg};
use dent::plot;
use dent::summary::Summary;
use dent::t_test::{SigLevel, TTest, welch_t_test};

use std::fs::File;
use std::path::Path;
use std::io::{self, BufRead, BufReader};

fn print_summary(s: &Summary) {
    println!("N\tMin\tMax\tMedian\tMean\tStdDev\tStdErr");
    println!(
        "{}\t{:0.2}\t{:0.2}\t{:0.2}\t{:0.2}\t{:0.2}\t{:0.2}",
        s.size(),
        s.min(),
        s.max(),
        s.median(),
        s.mean(),
        s.standard_deviation(),
        s.standard_error(),
    );
}

fn print_t_test(t_test: &TTest) {
    println!("T\tDF\tAlpha\tCrit\tRejectNull");
    println!(
        "{:0.3}\t{}\t{:0.3}\t{:0.3}\t{}",
        t_test.t,
        t_test.df,
        t_test.alpha,
        t_test.crit,
        t_test.reject,
    );
}

fn read_file(path: &str) -> Summary {
    let p = Path::new(path);
    let f = File::open(p).ok().unwrap();
    let r = BufReader::new(f);

    let data: Vec<f64> = r
        .lines()
        .map(|l| l.ok().unwrap().parse().unwrap())
        .collect();

    Summary::new(&data).unwrap()
}

fn parse_alpha(arg: &str) -> SigLevel {
    match arg {
        ".001" => SigLevel::Alpha001,
        ".005" => SigLevel::Alpha005,
        ".01"  => SigLevel::Alpha010,
        ".025" => SigLevel::Alpha025,
        ".05"  => SigLevel::Alpha050,
        ".1"   => SigLevel::Alpha100,
        _ => panic!(),
    }
}

fn summarize_stdin(draw_plot: bool, ascii: bool) {
    let stdin = io::stdin();

    let data: Vec<f64> = stdin
        .lock()
        .lines()
        .map(|l| l.ok().unwrap().parse().unwrap())
        .collect();

    let s = Summary::new(&data).unwrap();

    if draw_plot {
        if ascii {
            println!("{}\n", plot::ascii_summary_plot(&s, 80));
        } else {
            println!("{}\n", plot::summary_plot(&s, 80));
        }
    }

    print_summary(&s);
}

fn t_test_files(
    file1: &str,
    file2: &str,
    alpha: SigLevel,
    draw_plot: bool,
    ascii: bool,
) {
    let s1 = read_file(file1);
    let s2 = read_file(file2);

    let t_test = welch_t_test(&s1, &s2, alpha);

    if draw_plot {
        println!("{}\n", plot::comparison_plot(&s1, &s2, 80, ascii));
    }

    print_summary(&s1);
    println!();
    print_summary(&s2);
    println!();
    print_t_test(&t_test);
}

fn main() {
    let matches = App::new("dent")
        .version("0.1.0")
        .author("Joe Ranweiler <joe@lemma.co>")
        .about("A tiny tool for t-tests &c.")
        .arg(Arg::with_name("stdin")
             .short("s")
             .long("stdin")
             .help("Read and summarize data from stdin."))
        .arg(Arg::with_name("file1")
             .index(1)
             .value_name("FILE1")
             .takes_value(true)
             .required_unless("stdin")
             .help("1st file of sample data."))
        .arg(Arg::with_name("file2")
             .index(2)
             .value_name("FILE2")
             .takes_value(true)
             .required_unless("stdin")
             .help("2nd file of sample data."))
        .arg(Arg::with_name("alpha")
             .short("a")
             .long("alpha")
             .value_name("ALPHA")
             .help("Significance level α")
             .takes_value(true)
             .default_value(".05"))
        .arg(Arg::with_name("plot")
             .short("p")
             .long("plot")
             .help("Draw a box-and-whisker plot."))
        .arg(Arg::with_name("ascii")
             .long("ascii")
             .help("Use only ASCII characters in plots."))
        .get_matches();

    let ascii = matches.is_present("ascii");
    let draw_plot = matches.is_present("plot");
    let use_stdin = matches.is_present("stdin");

    if use_stdin {
        summarize_stdin(draw_plot, ascii);
    } else {
        let alpha = parse_alpha(matches.value_of("alpha").unwrap());
        let file1 = matches.value_of("file1").unwrap();
        let file2 = matches.value_of("file2").unwrap();

        t_test_files(file1, file2, alpha, draw_plot, ascii);
    }
}
<commit_msg>Unwrap results directly<commit_after>extern crate clap;
extern crate dent;

use clap::{App, Arg};
use dent::plot;
use dent::summary::Summary;
use dent::t_test::{SigLevel, TTest, welch_t_test};

use std::fs::File;
use std::path::Path;
use std::io::{self, BufRead, BufReader};

fn print_summary(s: &Summary) {
    println!("N\tMin\tMax\tMedian\tMean\tStdDev\tStdErr");
    println!(
        "{}\t{:0.2}\t{:0.2}\t{:0.2}\t{:0.2}\t{:0.2}\t{:0.2}",
        s.size(),
        s.min(),
        s.max(),
        s.median(),
        s.mean(),
        s.standard_deviation(),
        s.standard_error(),
    );
}

fn print_t_test(t_test: &TTest) {
    println!("T\tDF\tAlpha\tCrit\tRejectNull");
    println!(
        "{:0.3}\t{}\t{:0.3}\t{:0.3}\t{}",
        t_test.t,
        t_test.df,
        t_test.alpha,
        t_test.crit,
        t_test.reject,
    );
}

fn read_file(path: &str) -> Summary {
    let p = Path::new(path);
    let f = File::open(p).unwrap();
    let r = BufReader::new(f);

    let data: Vec<f64> = r
        .lines()
        .map(|l| l.unwrap().parse().unwrap())
        .collect();

    Summary::new(&data).unwrap()
}

fn parse_alpha(arg: &str) -> SigLevel {
    match arg {
        ".001" => SigLevel::Alpha001,
        ".005" => SigLevel::Alpha005,
        ".01"  => SigLevel::Alpha010,
        ".025" => SigLevel::Alpha025,
        ".05"  => SigLevel::Alpha050,
        ".1"   => SigLevel::Alpha100,
        _ => panic!(),
    }
}

fn summarize_stdin(draw_plot: bool, ascii: bool) {
    let stdin = io::stdin();

    let data: Vec<f64> = stdin
        .lock()
        .lines()
        .map(|l| l.unwrap().parse().unwrap())
        .collect();

    let s = Summary::new(&data).unwrap();

    if draw_plot {
        if ascii {
            println!("{}\n", plot::ascii_summary_plot(&s, 80));
        } else {
            println!("{}\n", plot::summary_plot(&s, 80));
        }
    }

    print_summary(&s);
}

fn t_test_files(
    file1: &str,
    file2: &str,
    alpha: SigLevel,
    draw_plot: bool,
    ascii: bool,
) {
    let s1 = read_file(file1);
    let s2 = read_file(file2);

    let t_test = welch_t_test(&s1, &s2, alpha);

    if draw_plot {
        println!("{}\n", plot::comparison_plot(&s1, &s2, 80, ascii));
    }

    print_summary(&s1);
    println!();
    print_summary(&s2);
    println!();
    print_t_test(&t_test);
}

fn main() {
    let matches = App::new("dent")
        .version("0.1.0")
        .author("Joe Ranweiler <joe@lemma.co>")
        .about("A tiny tool for t-tests &c.")
        .arg(Arg::with_name("stdin")
             .short("s")
             .long("stdin")
             .help("Read and summarize data from stdin."))
        .arg(Arg::with_name("file1")
             .index(1)
             .value_name("FILE1")
             .takes_value(true)
             .required_unless("stdin")
             .help("1st file of sample data."))
        .arg(Arg::with_name("file2")
             .index(2)
             .value_name("FILE2")
             .takes_value(true)
             .required_unless("stdin")
             .help("2nd file of sample data."))
        .arg(Arg::with_name("alpha")
             .short("a")
             .long("alpha")
             .value_name("ALPHA")
             .help("Significance level α")
             .takes_value(true)
             .default_value(".05"))
        .arg(Arg::with_name("plot")
             .short("p")
             .long("plot")
             .help("Draw a box-and-whisker plot."))
        .arg(Arg::with_name("ascii")
             .long("ascii")
             .help("Use only ASCII characters in plots."))
        .get_matches();

    let ascii = matches.is_present("ascii");
    let draw_plot = matches.is_present("plot");
    let use_stdin = matches.is_present("stdin");

    if use_stdin {
        summarize_stdin(draw_plot, ascii);
    } else {
        let alpha = parse_alpha(matches.value_of("alpha").unwrap());
        let file1 = matches.value_of("file1").unwrap();
        let file2 = matches.value_of("file2").unwrap();

        t_test_files(file1, file2, alpha, draw_plot, ascii);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

include!("../generated/butterfly.swim.rs");

pub use self::{membership::Health, swim::Payload as SwimPayload, swim::Type as SwimType};
<commit_msg>Establish baseline tests for `Ord` and `PartialOrd` for `Health`<commit_after>// Copyright (c) 2018 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

include!("../generated/butterfly.swim.rs");

pub use self::{membership::Health, swim::Payload as SwimPayload, swim::Type as SwimType};

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

    // These tests assure that we can properly compare Health values
    // along the spectrum of
    //
    //   Alive -> Suspect -> Confirmed -> Departed
    //
    // since that is important in our decision whether or not to
    // propagate membership rumors.

    #[test]
    fn alive_is_less_than_everything() {
        assert!(Health::Alive == Health::Alive);
        assert!(Health::Alive < Health::Suspect);
        assert!(Health::Alive < Health::Confirmed);
        assert!(Health::Alive < Health::Departed);
    }

    #[test]
    fn suspect_is_greater_than_alive_and_less_than_everything_else() {
        assert!(Health::Suspect > Health::Alive);
        assert!(Health::Suspect == Health::Suspect);
        assert!(Health::Suspect < Health::Confirmed);
        assert!(Health::Suspect < Health::Departed);
    }

    #[test]
    fn confirmed_is_greater_than_alive_and_suspect_but_less_than_departed() {
        assert!(Health::Confirmed > Health::Alive);
        assert!(Health::Confirmed > Health::Suspect);
        assert!(Health::Confirmed == Health::Confirmed);
        assert!(Health::Confirmed < Health::Departed);
    }

    #[test]
    fn departed_is_greater_than_everything() {
        assert!(Health::Departed > Health::Alive);
        assert!(Health::Departed > Health::Suspect);
        assert!(Health::Departed > Health::Confirmed);
        assert!(Health::Departed == Health::Departed);
    }
}
<|endoftext|>


<commit_before>use std::process::exit;
use xcb::base;
use colored::Colorize;

// A simple error enum for handling ruwm errors

#[derive(Debug)]
pub enum RuwmError {
	// Could not connect tothe X server
	CouldNotConnect(base::ConnError),
	// Could not acquire a scren from X server
	CouldNotAcquireScreen,
	// An atom used by the WM wasn't accepted by the X server
	CouldNotRegisterAtom(String),
	// Connection to the X server was interrupted
	ConnectionInterrupted,
	// Another WM was running and ruwm couldn't start
	OtherWmRunning,
	// Input/Output with X Server could not work
	IOError,
}

impl RuwmError {
	/// Print an error message and exit
	// TODO create a logger fn
	// Logger.error
	// Logger.warn
	// Logger.fatal
	// Logger.etc...etc...etc...
	// Different logs have different colors and some don't panic!
	// Logger doesn't have to only be used in errors, so worth it to make it a seperate struct
	pub fn handle(self) -> ! {
		match self {
			RuwmError::CouldNotConnect(e) => {
				return match e {
					base::ConnError::Connection => {
						panic!("{}", "Could not connect to X: socket, pipe or other stream error.".red())
					},
					base::ConnError::ClosedExtNotSupported => {
						panic!("{}", "Could not connect: X connection shutdown because extension not supported".red())
					},
					base::ConnError::ClosedMemInsufficient => {
						panic!("{}", "(Insufficient Memory) malloc(), calloc(), and realloc() error upon failure, for `eg: ENOMEM`".red())
					},
					base::ConnError::ClosedReqLenExceed => {
						panic!("{}", "Connection closed, exceeding request length that server accepts".red())
					},
					base::ConnError::ClosedParseErr => {
						panic!("{}", "Connection closed, error during parsing display string".red())
					},
					base::ConnError::ClosedInvalidScreen => {
						panic!("{}", "Connection closed because server does not have a screen matching the display".red())
					},
					base::ConnError::ClosedFdPassingFailed => {
						panic!("{}", "Connection closed because File Descriptor passing operation failed".red())
					},
					_ => panic!("{}", "Connection closed because of unknown error".red())
				};
			}
			RuwmError::CouldNotAcquireScreen => panic!("{}", "Could not acquire screen".red()),
			RuwmError::CouldNotRegisterAtom(e) => panic!("{} {}", "Could not register atom".red(), e.bold().red()),
			RuwmError::ConnectionInterrupted => panic!("{}", "Another WM is running, ruwm couldn't connect :-(".red()),
			RuwmError::IOError => panic!("{}", "IO Error!".red()),
			_ => panic!("{}", "Something unexpected happened! Exiting...".red()),
		};
	}
}
<commit_msg>edited todo before i forget<commit_after>use std::process::exit;
use xcb::base;
use colored::Colorize;

// A simple error enum for handling ruwm errors

#[derive(Debug)]
pub enum RuwmError {
	// Could not connect tothe X server
	CouldNotConnect(base::ConnError),
	// Could not acquire a scren from X server
	CouldNotAcquireScreen,
	// An atom used by the WM wasn't accepted by the X server
	CouldNotRegisterAtom(String),
	// Connection to the X server was interrupted
	ConnectionInterrupted,
	// Another WM was running and ruwm couldn't start
	OtherWmRunning,
	// Input/Output with X Server could not work
	IOError,
}

impl RuwmError {
	/// Print an error message and exit
	// TODO create a logger fn (Maybe better to make a macro?)
	// Logger.error
	// Logger.warn
	// Logger.fatal
	// Logger.etc...etc...etc...
	// Different logs have different colors and some don't panic!
	// Logger doesn't have to only be used in errors, so worth it to make it a seperate struct
	pub fn handle(self) -> ! {
		match self {
			RuwmError::CouldNotConnect(e) => {
				return match e {
					base::ConnError::Connection => {
						panic!("{}", "Could not connect to X: socket, pipe or other stream error.".red())
					},
					base::ConnError::ClosedExtNotSupported => {
						panic!("{}", "Could not connect: X connection shutdown because extension not supported".red())
					},
					base::ConnError::ClosedMemInsufficient => {
						panic!("{}", "(Insufficient Memory) malloc(), calloc(), and realloc() error upon failure, for `eg: ENOMEM`".red())
					},
					base::ConnError::ClosedReqLenExceed => {
						panic!("{}", "Connection closed, exceeding request length that server accepts".red())
					},
					base::ConnError::ClosedParseErr => {
						panic!("{}", "Connection closed, error during parsing display string".red())
					},
					base::ConnError::ClosedInvalidScreen => {
						panic!("{}", "Connection closed because server does not have a screen matching the display".red())
					},
					base::ConnError::ClosedFdPassingFailed => {
						panic!("{}", "Connection closed because File Descriptor passing operation failed".red())
					},
					_ => panic!("{}", "Connection closed because of unknown error".red())
				};
			}
			RuwmError::CouldNotAcquireScreen => panic!("{}", "Could not acquire screen".red()),
			RuwmError::CouldNotRegisterAtom(e) => panic!("{} {}", "Could not register atom".red(), e.bold().red()),
			RuwmError::ConnectionInterrupted => panic!("{}", "Another WM is running, ruwm couldn't connect :-(".red()),
			RuwmError::IOError => panic!("{}", "IO Error!".red()),
			_ => panic!("{}", "Something unexpected happened! Exiting...".red()),
		};
	}
}
<|endoftext|>


<commit_before>// information from https://raw.githubusercontent.com/torvalds/linux/master/
//                  /include/uapi/linux/can/error.h

use try_from::TryFrom;
use super::CanFrame;
use std::error::Error;
use std::{error, fmt};

#[inline]
/// Helper function to retrieve a specific byte of frame data or returning an
/// `Err(..)` otherwise.
fn get_data(frame: &CanFrame, idx: u8) -> Result<u8, CanErrorDecodingFailure> {
    Ok(*(frame.data().get(idx as usize).ok_or(CanErrorDecodingFailure::NotEnoughData(idx)))?)
}

/// Error decoding a CanError from a CanFrame.
#[derive(Copy, Clone, Debug)]
pub enum CanErrorDecodingFailure {
    /// The supplied CanFrame did not have the error bit set.
    NotAnError,

    /// The error type is not known and cannot be decoded.
    UnknownErrorType(u32),

    /// The error type indicated a need for additional information as `data`,
    /// but the `data` field was not long enough.
    NotEnoughData(u8),

    /// The error type `ControllerProblem` was indicated and additional
    /// information found, but not recognized.
    InvalidControllerProblem,

    /// The type of the ProtocolViolation was not valid
    InvalidViolationType,

    /// A location was specified for a ProtocolViolation, but the location
    /// was not valid.
    InvalidLocation,

    /// The supplied transciever error was invalid.
    InvalidTransceiverError,
}

impl error::Error for CanErrorDecodingFailure {
    fn description(&self) -> &str {
        match *self {
            CanErrorDecodingFailure::NotAnError => "CAN frame is not an error",
            CanErrorDecodingFailure::UnknownErrorType(_) => "unknown error type",
            CanErrorDecodingFailure::NotEnoughData(_) => "not enough data",
            CanErrorDecodingFailure::InvalidControllerProblem => "not a valid controller problem",
            CanErrorDecodingFailure::InvalidViolationType => "not a valid violation type",
            CanErrorDecodingFailure::InvalidLocation => "not a valid location",
            CanErrorDecodingFailure::InvalidTransceiverError => "not a valid transceiver error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for CanErrorDecodingFailure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

#[derive(Copy, Clone, Debug)]
pub enum CanError {
    /// TX timeout (by netdevice driver)
    TransmitTimeout,

    /// Arbitration was lost. Contains the number after which arbitration was
    /// lost or 0 if unspecified
    LostArbitration(u8),

    /// Controller problem, see `ControllerProblem`
    ControllerProblem(ControllerProblem),

    /// Protocol violation at the specified `Location`. See `ProtocolViolation`
    /// for details.
    ProtocolViolation {
        vtype: ViolationType,
        location: Location,
    },

    /// Transceiver Error.
    TransceiverError,

    /// No ACK received for current CAN frame.
    NoAck,

    /// Bus off (due to too many detected errors)
    BusOff,

    /// Bus error (due to too many detected errors)
    BusError,

    /// The bus has been restarted
    Restarted,

    /// Unknown, possibly invalid, error
    Unknown(u32),
}

impl error::Error for CanError {
    fn description(&self) -> &str {
        match *self {
            CanError::TransmitTimeout => "transmission timeout",
            CanError::LostArbitration(_) => "arbitration lost",
            CanError::ControllerProblem(_) => "controller problem",
            CanError::ProtocolViolation { .. } => "protocol violation",
            CanError::TransceiverError => "transceiver error",
            CanError::NoAck => "no ack",
            CanError::BusOff => "bus off",
            CanError::BusError => "bus error",
            CanError::Restarted => "restarted",
            CanError::Unknown(_) => "unknown error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CanError::ControllerProblem(ref e) => Some(e),
            _ => None,
        }
    }
}

impl fmt::Display for CanError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CanError::LostArbitration(n) => write!(f, "arbitration lost after {} bits", n),
            CanError::ControllerProblem(e) => write!(f, "controller problem: {}", e),
            CanError::ProtocolViolation { vtype, location } => {
                write!(f, "protocol violation at {}: {}", location, vtype)
            }
            CanError::Unknown(errno) => write!(f, "unknown error ({})", errno),
            _ => write!(f, "{}", self.description()),
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub enum ControllerProblem {
    // unspecified
    Unspecified,

    // RX buffer overflow
    ReceiveBufferOverflow,

    // TX buffer overflow
    TransmitBufferOverflow,

    // reached warning level for RX errors
    ReceiveErrorWarning,

    // reached warning level for TX errors
    TransmitErrorWarning,

    // reached error passive status RX
    ReceiveErrorPassive,

    // reached error passive status TX
    TransmitErrorPassive,

    // recovered to error active state
    Active,
}

impl error::Error for ControllerProblem {
    fn description(&self) -> &str {
        match *self {
            ControllerProblem::Unspecified => "unspecified controller problem",
            ControllerProblem::ReceiveBufferOverflow => "receive buffer overflow",
            ControllerProblem::TransmitBufferOverflow => "transmit buffer overflow",
            ControllerProblem::ReceiveErrorWarning => "ERROR WARNING (receive)",
            ControllerProblem::TransmitErrorWarning => "ERROR WARNING (transmit)",
            ControllerProblem::ReceiveErrorPassive => "ERROR PASSIVE (receive)",
            ControllerProblem::TransmitErrorPassive => "ERROR PASSIVE (transmit)",
            ControllerProblem::Active => "ERROR ACTIVE",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for ControllerProblem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl TryFrom<u8> for ControllerProblem {
    type Err = CanErrorDecodingFailure;

    fn try_from(val: u8) -> Result<ControllerProblem, CanErrorDecodingFailure> {
        Ok(match val {
            0x00 => ControllerProblem::Unspecified,
            0x01 => ControllerProblem::ReceiveBufferOverflow,
            0x02 => ControllerProblem::TransmitBufferOverflow,
            0x04 => ControllerProblem::ReceiveErrorWarning,
            0x08 => ControllerProblem::TransmitErrorWarning,
            0x10 => ControllerProblem::ReceiveErrorPassive,
            0x20 => ControllerProblem::TransmitErrorPassive,
            0x40 => ControllerProblem::Active,
            _ => return Err(CanErrorDecodingFailure::InvalidControllerProblem),
        })
    }
}

#[derive(Copy, Clone, Debug)]
pub enum ViolationType {
    /// Unspecified Violation
    Unspecified,

    /// Single Bit Error
    SingleBitError,

    /// Frame formatting error
    FrameFormatError,

    /// Bit stuffing error
    BitStuffingError,

    /// A dominant bit was sent, but not received
    UnableToSendDominantBit,

    /// A recessive bit was sent, but not received
    UnableToSendRecessiveBit,

    /// Bus overloaded
    BusOverload,

    /// Bus is active (again)
    Active,

    /// Transmission Error
    TransmissionError,
}

impl error::Error for ViolationType {
    fn description(&self) -> &str {
        match *self {
            ViolationType::Unspecified => "unspecified",
            ViolationType::SingleBitError => "single bit error",
            ViolationType::FrameFormatError => "frame format error",
            ViolationType::BitStuffingError => "bit stuffing error",
            ViolationType::UnableToSendDominantBit => "unable to send dominant bit",
            ViolationType::UnableToSendRecessiveBit => "unable to send recessive bit",
            ViolationType::BusOverload => "bus overload",
            ViolationType::Active => "active",
            ViolationType::TransmissionError => "transmission error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for ViolationType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl TryFrom<u8> for ViolationType {
    type Err = CanErrorDecodingFailure;

    fn try_from(val: u8) -> Result<ViolationType, CanErrorDecodingFailure> {
        Ok(match val {
            0x00 => ViolationType::Unspecified,
            0x01 => ViolationType::SingleBitError,
            0x02 => ViolationType::FrameFormatError,
            0x04 => ViolationType::BitStuffingError,
            0x08 => ViolationType::UnableToSendDominantBit,
            0x10 => ViolationType::UnableToSendRecessiveBit,
            0x20 => ViolationType::BusOverload,
            0x40 => ViolationType::Active,
            0x80 => ViolationType::TransmissionError,
            _ => return Err(CanErrorDecodingFailure::InvalidViolationType),
        })
    }
}

/// Location
///
/// Describes where inside a received frame an error occured.
#[derive(Copy, Clone, Debug)]
pub enum Location {
    /// Unspecified
    Unspecified,

    /// Start of frame.
    StartOfFrame,

    /// ID bits 28-21 (SFF: 10-3)
    Id2821,

    /// ID bits 20-18 (SFF: 2-0)
    Id2018,

    /// substitute RTR (SFF: RTR)
    SubstituteRtr,

    /// extension of identifier
    IdentifierExtension,

    /// ID bits 17-13
    Id1713,

    /// ID bits 12-5
    Id1205,

    /// ID bits 4-0
    Id0400,

    /// RTR bit
    Rtr,

    /// Reserved bit 1
    Reserved1,

    /// Reserved bit 0
    Reserved0,

    /// Data length
    DataLengthCode,

    /// Data section
    DataSection,

    /// CRC sequence
    CrcSequence,

    /// CRC delimiter
    CrcDelimiter,

    /// ACK slot
    AckSlot,

    /// ACK delimiter
    AckDelimiter,

    /// End-of-frame
    EndOfFrame,

    /// Intermission (between frames)
    Intermission,
}

impl fmt::Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Location::Unspecified => "unspecified location",
                   Location::StartOfFrame => "start of frame",
                   Location::Id2821 => "ID, bits 28-21",
                   Location::Id2018 => "ID, bits 20-18",
                   Location::SubstituteRtr => "substitute RTR bit",
                   Location::IdentifierExtension => "ID, extension",
                   Location::Id1713 => "ID, bits 17-13",
                   Location::Id1205 => "ID, bits 12-05",
                   Location::Id0400 => "ID, bits 04-00",
                   Location::Rtr => "RTR bit",
                   Location::Reserved1 => "reserved bit 1",
                   Location::Reserved0 => "reserved bit 0",
                   Location::DataLengthCode => "data length code",
                   Location::DataSection => "data section",
                   Location::CrcSequence => "CRC sequence",
                   Location::CrcDelimiter => "CRC delimiter",
                   Location::AckSlot => "ACK slot",
                   Location::AckDelimiter => "ACK delimiter",
                   Location::EndOfFrame => "end of frame",
                   Location::Intermission => "intermission",
               })
    }
}
impl TryFrom<u8> for Location {
    type Err = CanErrorDecodingFailure;

    fn try_from(val: u8) -> Result<Location, CanErrorDecodingFailure> {
        Ok(match val {
            0x00 => Location::Unspecified,
            0x03 => Location::StartOfFrame,
            0x02 => Location::Id2821,
            0x06 => Location::Id2018,
            0x04 => Location::SubstituteRtr,
            0x05 => Location::IdentifierExtension,
            0x07 => Location::Id1713,
            0x0F => Location::Id1205,
            0x0E => Location::Id0400,
            0x0C => Location::Rtr,
            0x0D => Location::Reserved1,
            0x09 => Location::Reserved0,
            0x0B => Location::DataLengthCode,
            0x0A => Location::DataSection,
            0x08 => Location::CrcSequence,
            0x18 => Location::CrcDelimiter,
            0x19 => Location::AckSlot,
            0x1B => Location::AckDelimiter,
            0x1A => Location::EndOfFrame,
            0x12 => Location::Intermission,
            _ => return Err(CanErrorDecodingFailure::InvalidLocation),
        })
    }
}

pub enum TransceiverError {
    Unspecified,
    CanHighNoWire,
    CanHighShortToBat,
    CanHighShortToVcc,
    CanHighShortToGnd,
    CanLowNoWire,
    CanLowShortToBat,
    CanLowShortToVcc,
    CanLowShortToGnd,
    CanLowShortToCanHigh,
}

impl TryFrom<u8> for TransceiverError {
    type Err = CanErrorDecodingFailure;

    fn try_from(val: u8) -> Result<TransceiverError, CanErrorDecodingFailure> {
        Ok(match val {
            0x00 => TransceiverError::Unspecified,
            0x04 => TransceiverError::CanHighNoWire,
            0x05 => TransceiverError::CanHighShortToBat,
            0x06 => TransceiverError::CanHighShortToVcc,
            0x07 => TransceiverError::CanHighShortToGnd,
            0x40 => TransceiverError::CanLowNoWire,
            0x50 => TransceiverError::CanLowShortToBat,
            0x60 => TransceiverError::CanLowShortToVcc,
            0x70 => TransceiverError::CanLowShortToGnd,
            0x80 => TransceiverError::CanLowShortToCanHigh,
            _ => return Err(CanErrorDecodingFailure::InvalidTransceiverError),
        })
    }
}

impl CanError {
    pub fn from_frame(frame: &CanFrame) -> Result<CanError, CanErrorDecodingFailure> {
        if !frame.is_error() {
            return Err(CanErrorDecodingFailure::NotAnError);
        }

        match frame.err() {
            0x00000001 => Ok(CanError::TransmitTimeout),
            0x00000002 => Ok(CanError::LostArbitration(get_data(frame, 0)?)),
            0x00000004 => {
                Ok(CanError::ControllerProblem(ControllerProblem::try_from(get_data(frame, 1)?)?))
            }

            0x00000008 => {
                Ok(CanError::ProtocolViolation {
                    vtype: ViolationType::try_from(get_data(frame, 2)?)?,
                    location: Location::try_from(get_data(frame, 3)?)?,
                })
            }

            0x00000010 => Ok(CanError::TransceiverError),
            0x00000020 => Ok(CanError::NoAck),
            0x00000040 => Ok(CanError::BusOff),
            0x00000080 => Ok(CanError::BusError),
            0x00000100 => Ok(CanError::Restarted),
            e => Err(CanErrorDecodingFailure::UnknownErrorType(e)),
        }
    }
}

pub trait ControllerSpecificErrorInformation {
    fn get_ctrl_err(&self) -> Option<&[u8]>;
}

impl ControllerSpecificErrorInformation for CanFrame {
    #[inline]
    fn get_ctrl_err(&self) -> Option<&[u8]> {
        let data = self.data();

        if data.len() != 8 {
            None
        } else {
            Some(&data[5..])
        }
    }
}
<commit_msg>Use ok_or_else instead of ok_or.<commit_after>// information from https://raw.githubusercontent.com/torvalds/linux/master/
//                  /include/uapi/linux/can/error.h

use try_from::TryFrom;
use super::CanFrame;
use std::error::Error;
use std::{error, fmt};

#[inline]
/// Helper function to retrieve a specific byte of frame data or returning an
/// `Err(..)` otherwise.
fn get_data(frame: &CanFrame, idx: u8) -> Result<u8, CanErrorDecodingFailure> {
    Ok(*(frame.data()
        .get(idx as usize)
        .ok_or_else(|| CanErrorDecodingFailure::NotEnoughData(idx)))?)
}

/// Error decoding a CanError from a CanFrame.
#[derive(Copy, Clone, Debug)]
pub enum CanErrorDecodingFailure {
    /// The supplied CanFrame did not have the error bit set.
    NotAnError,

    /// The error type is not known and cannot be decoded.
    UnknownErrorType(u32),

    /// The error type indicated a need for additional information as `data`,
    /// but the `data` field was not long enough.
    NotEnoughData(u8),

    /// The error type `ControllerProblem` was indicated and additional
    /// information found, but not recognized.
    InvalidControllerProblem,

    /// The type of the ProtocolViolation was not valid
    InvalidViolationType,

    /// A location was specified for a ProtocolViolation, but the location
    /// was not valid.
    InvalidLocation,

    /// The supplied transciever error was invalid.
    InvalidTransceiverError,
}

impl error::Error for CanErrorDecodingFailure {
    fn description(&self) -> &str {
        match *self {
            CanErrorDecodingFailure::NotAnError => "CAN frame is not an error",
            CanErrorDecodingFailure::UnknownErrorType(_) => "unknown error type",
            CanErrorDecodingFailure::NotEnoughData(_) => "not enough data",
            CanErrorDecodingFailure::InvalidControllerProblem => "not a valid controller problem",
            CanErrorDecodingFailure::InvalidViolationType => "not a valid violation type",
            CanErrorDecodingFailure::InvalidLocation => "not a valid location",
            CanErrorDecodingFailure::InvalidTransceiverError => "not a valid transceiver error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for CanErrorDecodingFailure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

#[derive(Copy, Clone, Debug)]
pub enum CanError {
    /// TX timeout (by netdevice driver)
    TransmitTimeout,

    /// Arbitration was lost. Contains the number after which arbitration was
    /// lost or 0 if unspecified
    LostArbitration(u8),

    /// Controller problem, see `ControllerProblem`
    ControllerProblem(ControllerProblem),

    /// Protocol violation at the specified `Location`. See `ProtocolViolation`
    /// for details.
    ProtocolViolation {
        vtype: ViolationType,
        location: Location,
    },

    /// Transceiver Error.
    TransceiverError,

    /// No ACK received for current CAN frame.
    NoAck,

    /// Bus off (due to too many detected errors)
    BusOff,

    /// Bus error (due to too many detected errors)
    BusError,

    /// The bus has been restarted
    Restarted,

    /// Unknown, possibly invalid, error
    Unknown(u32),
}

impl error::Error for CanError {
    fn description(&self) -> &str {
        match *self {
            CanError::TransmitTimeout => "transmission timeout",
            CanError::LostArbitration(_) => "arbitration lost",
            CanError::ControllerProblem(_) => "controller problem",
            CanError::ProtocolViolation { .. } => "protocol violation",
            CanError::TransceiverError => "transceiver error",
            CanError::NoAck => "no ack",
            CanError::BusOff => "bus off",
            CanError::BusError => "bus error",
            CanError::Restarted => "restarted",
            CanError::Unknown(_) => "unknown error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CanError::ControllerProblem(ref e) => Some(e),
            _ => None,
        }
    }
}

impl fmt::Display for CanError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CanError::LostArbitration(n) => write!(f, "arbitration lost after {} bits", n),
            CanError::ControllerProblem(e) => write!(f, "controller problem: {}", e),
            CanError::ProtocolViolation { vtype, location } => {
                write!(f, "protocol violation at {}: {}", location, vtype)
            }
            CanError::Unknown(errno) => write!(f, "unknown error ({})", errno),
            _ => write!(f, "{}", self.description()),
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub enum ControllerProblem {
    // unspecified
    Unspecified,

    // RX buffer overflow
    ReceiveBufferOverflow,

    // TX buffer overflow
    TransmitBufferOverflow,

    // reached warning level for RX errors
    ReceiveErrorWarning,

    // reached warning level for TX errors
    TransmitErrorWarning,

    // reached error passive status RX
    ReceiveErrorPassive,

    // reached error passive status TX
    TransmitErrorPassive,

    // recovered to error active state
    Active,
}

impl error::Error for ControllerProblem {
    fn description(&self) -> &str {
        match *self {
            ControllerProblem::Unspecified => "unspecified controller problem",
            ControllerProblem::ReceiveBufferOverflow => "receive buffer overflow",
            ControllerProblem::TransmitBufferOverflow => "transmit buffer overflow",
            ControllerProblem::ReceiveErrorWarning => "ERROR WARNING (receive)",
            ControllerProblem::TransmitErrorWarning => "ERROR WARNING (transmit)",
            ControllerProblem::ReceiveErrorPassive => "ERROR PASSIVE (receive)",
            ControllerProblem::TransmitErrorPassive => "ERROR PASSIVE (transmit)",
            ControllerProblem::Active => "ERROR ACTIVE",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for ControllerProblem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl TryFrom<u8> for ControllerProblem {
    type Err = CanErrorDecodingFailure;

    fn try_from(val: u8) -> Result<ControllerProblem, CanErrorDecodingFailure> {
        Ok(match val {
            0x00 => ControllerProblem::Unspecified,
            0x01 => ControllerProblem::ReceiveBufferOverflow,
            0x02 => ControllerProblem::TransmitBufferOverflow,
            0x04 => ControllerProblem::ReceiveErrorWarning,
            0x08 => ControllerProblem::TransmitErrorWarning,
            0x10 => ControllerProblem::ReceiveErrorPassive,
            0x20 => ControllerProblem::TransmitErrorPassive,
            0x40 => ControllerProblem::Active,
            _ => return Err(CanErrorDecodingFailure::InvalidControllerProblem),
        })
    }
}

#[derive(Copy, Clone, Debug)]
pub enum ViolationType {
    /// Unspecified Violation
    Unspecified,

    /// Single Bit Error
    SingleBitError,

    /// Frame formatting error
    FrameFormatError,

    /// Bit stuffing error
    BitStuffingError,

    /// A dominant bit was sent, but not received
    UnableToSendDominantBit,

    /// A recessive bit was sent, but not received
    UnableToSendRecessiveBit,

    /// Bus overloaded
    BusOverload,

    /// Bus is active (again)
    Active,

    /// Transmission Error
    TransmissionError,
}

impl error::Error for ViolationType {
    fn description(&self) -> &str {
        match *self {
            ViolationType::Unspecified => "unspecified",
            ViolationType::SingleBitError => "single bit error",
            ViolationType::FrameFormatError => "frame format error",
            ViolationType::BitStuffingError => "bit stuffing error",
            ViolationType::UnableToSendDominantBit => "unable to send dominant bit",
            ViolationType::UnableToSendRecessiveBit => "unable to send recessive bit",
            ViolationType::BusOverload => "bus overload",
            ViolationType::Active => "active",
            ViolationType::TransmissionError => "transmission error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for ViolationType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl TryFrom<u8> for ViolationType {
    type Err = CanErrorDecodingFailure;

    fn try_from(val: u8) -> Result<ViolationType, CanErrorDecodingFailure> {
        Ok(match val {
            0x00 => ViolationType::Unspecified,
            0x01 => ViolationType::SingleBitError,
            0x02 => ViolationType::FrameFormatError,
            0x04 => ViolationType::BitStuffingError,
            0x08 => ViolationType::UnableToSendDominantBit,
            0x10 => ViolationType::UnableToSendRecessiveBit,
            0x20 => ViolationType::BusOverload,
            0x40 => ViolationType::Active,
            0x80 => ViolationType::TransmissionError,
            _ => return Err(CanErrorDecodingFailure::InvalidViolationType),
        })
    }
}

/// Location
///
/// Describes where inside a received frame an error occured.
#[derive(Copy, Clone, Debug)]
pub enum Location {
    /// Unspecified
    Unspecified,

    /// Start of frame.
    StartOfFrame,

    /// ID bits 28-21 (SFF: 10-3)
    Id2821,

    /// ID bits 20-18 (SFF: 2-0)
    Id2018,

    /// substitute RTR (SFF: RTR)
    SubstituteRtr,

    /// extension of identifier
    IdentifierExtension,

    /// ID bits 17-13
    Id1713,

    /// ID bits 12-5
    Id1205,

    /// ID bits 4-0
    Id0400,

    /// RTR bit
    Rtr,

    /// Reserved bit 1
    Reserved1,

    /// Reserved bit 0
    Reserved0,

    /// Data length
    DataLengthCode,

    /// Data section
    DataSection,

    /// CRC sequence
    CrcSequence,

    /// CRC delimiter
    CrcDelimiter,

    /// ACK slot
    AckSlot,

    /// ACK delimiter
    AckDelimiter,

    /// End-of-frame
    EndOfFrame,

    /// Intermission (between frames)
    Intermission,
}

impl fmt::Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Location::Unspecified => "unspecified location",
                   Location::StartOfFrame => "start of frame",
                   Location::Id2821 => "ID, bits 28-21",
                   Location::Id2018 => "ID, bits 20-18",
                   Location::SubstituteRtr => "substitute RTR bit",
                   Location::IdentifierExtension => "ID, extension",
                   Location::Id1713 => "ID, bits 17-13",
                   Location::Id1205 => "ID, bits 12-05",
                   Location::Id0400 => "ID, bits 04-00",
                   Location::Rtr => "RTR bit",
                   Location::Reserved1 => "reserved bit 1",
                   Location::Reserved0 => "reserved bit 0",
                   Location::DataLengthCode => "data length code",
                   Location::DataSection => "data section",
                   Location::CrcSequence => "CRC sequence",
                   Location::CrcDelimiter => "CRC delimiter",
                   Location::AckSlot => "ACK slot",
                   Location::AckDelimiter => "ACK delimiter",
                   Location::EndOfFrame => "end of frame",
                   Location::Intermission => "intermission",
               })
    }
}
impl TryFrom<u8> for Location {
    type Err = CanErrorDecodingFailure;

    fn try_from(val: u8) -> Result<Location, CanErrorDecodingFailure> {
        Ok(match val {
            0x00 => Location::Unspecified,
            0x03 => Location::StartOfFrame,
            0x02 => Location::Id2821,
            0x06 => Location::Id2018,
            0x04 => Location::SubstituteRtr,
            0x05 => Location::IdentifierExtension,
            0x07 => Location::Id1713,
            0x0F => Location::Id1205,
            0x0E => Location::Id0400,
            0x0C => Location::Rtr,
            0x0D => Location::Reserved1,
            0x09 => Location::Reserved0,
            0x0B => Location::DataLengthCode,
            0x0A => Location::DataSection,
            0x08 => Location::CrcSequence,
            0x18 => Location::CrcDelimiter,
            0x19 => Location::AckSlot,
            0x1B => Location::AckDelimiter,
            0x1A => Location::EndOfFrame,
            0x12 => Location::Intermission,
            _ => return Err(CanErrorDecodingFailure::InvalidLocation),
        })
    }
}

pub enum TransceiverError {
    Unspecified,
    CanHighNoWire,
    CanHighShortToBat,
    CanHighShortToVcc,
    CanHighShortToGnd,
    CanLowNoWire,
    CanLowShortToBat,
    CanLowShortToVcc,
    CanLowShortToGnd,
    CanLowShortToCanHigh,
}

impl TryFrom<u8> for TransceiverError {
    type Err = CanErrorDecodingFailure;

    fn try_from(val: u8) -> Result<TransceiverError, CanErrorDecodingFailure> {
        Ok(match val {
            0x00 => TransceiverError::Unspecified,
            0x04 => TransceiverError::CanHighNoWire,
            0x05 => TransceiverError::CanHighShortToBat,
            0x06 => TransceiverError::CanHighShortToVcc,
            0x07 => TransceiverError::CanHighShortToGnd,
            0x40 => TransceiverError::CanLowNoWire,
            0x50 => TransceiverError::CanLowShortToBat,
            0x60 => TransceiverError::CanLowShortToVcc,
            0x70 => TransceiverError::CanLowShortToGnd,
            0x80 => TransceiverError::CanLowShortToCanHigh,
            _ => return Err(CanErrorDecodingFailure::InvalidTransceiverError),
        })
    }
}

impl CanError {
    pub fn from_frame(frame: &CanFrame) -> Result<CanError, CanErrorDecodingFailure> {
        if !frame.is_error() {
            return Err(CanErrorDecodingFailure::NotAnError);
        }

        match frame.err() {
            0x00000001 => Ok(CanError::TransmitTimeout),
            0x00000002 => Ok(CanError::LostArbitration(get_data(frame, 0)?)),
            0x00000004 => {
                Ok(CanError::ControllerProblem(ControllerProblem::try_from(get_data(frame, 1)?)?))
            }

            0x00000008 => {
                Ok(CanError::ProtocolViolation {
                    vtype: ViolationType::try_from(get_data(frame, 2)?)?,
                    location: Location::try_from(get_data(frame, 3)?)?,
                })
            }

            0x00000010 => Ok(CanError::TransceiverError),
            0x00000020 => Ok(CanError::NoAck),
            0x00000040 => Ok(CanError::BusOff),
            0x00000080 => Ok(CanError::BusError),
            0x00000100 => Ok(CanError::Restarted),
            e => Err(CanErrorDecodingFailure::UnknownErrorType(e)),
        }
    }
}

pub trait ControllerSpecificErrorInformation {
    fn get_ctrl_err(&self) -> Option<&[u8]>;
}

impl ControllerSpecificErrorInformation for CanFrame {
    #[inline]
    fn get_ctrl_err(&self) -> Option<&[u8]> {
        let data = self.data();

        if data.len() != 8 {
            None
        } else {
            Some(&data[5..])
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::io::Write;
use std::process::{Command, Stdio};
use std::path::{Path, PathBuf};

pub struct Git {
    pub host: String,
    pub token: String,
    repo_dir: PathBuf,
}

impl Git {
    pub fn new(host: &str, token: &str, repo_dir: &Path) -> Git {
        Git {
            host: host.to_string(),
            token: token.to_string(),
            repo_dir: repo_dir.to_owned(),
        }
    }

    pub fn run(&self, args: &[&str]) -> Result<String, String> {
        self.do_run(args, None)
    }

    pub fn run_with_stdin(&self, args: &[&str], stdin: &str) -> Result<String, String> {
        self.do_run(args, Some(stdin))
    }

    fn ask_pass_path(&self) -> String {
        let ask_pass = "octobot-ask-pass";
        match env::current_exe() {
            Ok(ref exe) if exe.parent().is_some() => {
                exe.parent().unwrap().join(ask_pass).to_string_lossy().into_owned()
            }
            _ => ask_pass.to_string(),
        }
    }

    pub fn has_branch(&self, branch: &str) -> Result<bool, String> {
        let output = try!(self.run(&["branch"]));
        // skip first two characters for the bullet point
        Ok(output.lines().any(|b| b.len() > 2 && branch == &b[2..]))
    }

    pub fn current_branch(&self) -> Result<String, String> {
        self.run(&["rev-parse", "--abbrev-ref", "HEAD"])
    }

    pub fn does_branch_contain(&self, git_ref: &str, branch: &str) -> Result<bool, String> {
        let output = try!(self.run(&["branch", "--contains", git_ref]));
        // return branches, stripping out the bullet point
        Ok(output.lines().any(|b| b.len() > 2 && branch == &b[2..]))
    }

    // Find the commit at which |leaf_ref| forked from |base_branch|.
    // This can find which commits belong to a PR.
    // Returns the ref found in the base branch that this git_ref came from.
    pub fn find_base_branch_commit(&self, leaf_ref: &str, base_branch: &str) -> Result<String, String> {
        self.run(&["merge-base", "--fork-point", base_branch, leaf_ref])
    }

    pub fn clean(&self) -> Result<(), String> {
        try!(self.run(&["reset", "--hard"]));
        try!(self.run(&["clean", "-fdx"]));
        Ok(())
    }

    // checking a branch named |new_branch_name| and ensure it is up to date with |source_branch|
    // |source_branch| can be a commit hash or an origin/branch-name.
    pub fn checkout_branch(&self, new_branch_name: &str, source_branch: &str) ->  Result<(), String> {
        let current_branch = try!(self.current_branch());
        if current_branch == new_branch_name {
            try!(self.run(&["reset", "--hard", &source_branch]));
        } else {
            // delete if it exists
            let has_branch = try!(self.has_branch(new_branch_name));
            if has_branch {
                try!(self.run(&["branch", "-D", new_branch_name]));
            }
            // recreate branch
            try!(self.run(&["checkout", "-b", new_branch_name, &source_branch]));
        }

        Ok(())
    }

    pub fn diff(&self, base: &str, head: &str) -> Result<String, String> {
        self.run(&["diff", base, head, "-w"])
    }

    // returns (title, body)
    pub fn get_commit_desc(&self, commit_hash: &str) -> Result<(String, String), String> {
        let lines: Vec<String> = try!(self.run(&["log", "-1", "--pretty=%B", commit_hash]))
            .split("\n")
            .map(|l| l.trim().to_string())
            .collect();

        if lines.len() == 0 {
            return Err(format!("Empty commit message found!"));
        }

        let title = lines[0].clone();

        let mut body = String::new();
        // skip the blank line
        if lines.len() > 2 {
            body = lines[2..].join("\n");
            body += "\n";
        }

        Ok((title, body))
    }

    fn do_run(&self, args: &[&str], stdin: Option<&str>) -> Result<String, String> {
        debug!("Running git with args: {:?}", args);
        let cmd = Command::new("git")
            .current_dir(&self.repo_dir)
            .stdin(if stdin.is_some() {
                Stdio::piped()
            } else {
                Stdio::null()
            })
            .stderr(Stdio::piped())
            .stdout(Stdio::piped())
            .args(args)
            .env("GIT_ASKPASS", &self.ask_pass_path())
            .env("OCTOBOT_HOST", &self.host)
            .env("OCTOBOT_PASS", &self.token)
            .spawn();

        let mut child = match cmd {
            Ok(c) => c,
            Err(e) => return Err(format!("Error starting git: {}", e)),
        };

        if let Some(ref stdin) = stdin {
            if let Some(ref mut child_stdin) = child.stdin {
                if let Err(e) = child_stdin.write_all(stdin.as_bytes()) {
                    return Err(format!("Error writing to stdin: {}", e));
                }
            }
        }

        let result = match child.wait_with_output() {
            Ok(r) => r,
            Err(e) => return Err(format!("Error running git: {}", e)),
        };

        let mut output = String::new();
        if result.stdout.len() > 0 {
            output += String::from_utf8_lossy(&result.stdout).as_ref();
        }

        if !result.status.success() {
            if result.stderr.len() > 0 {
                output += String::from_utf8_lossy(&result.stderr).as_ref();
            }
            Err(format!("Error running git (exit code {}):\n{}",
                        result.status.code().unwrap_or(-1),
                        output))
        } else {

            Ok(output.trim().to_string())
        }
    }
}
<commit_msg>Stop using --fork-point (#58)<commit_after>use std::env;
use std::io::Write;
use std::process::{Command, Stdio};
use std::path::{Path, PathBuf};

pub struct Git {
    pub host: String,
    pub token: String,
    repo_dir: PathBuf,
}

impl Git {
    pub fn new(host: &str, token: &str, repo_dir: &Path) -> Git {
        Git {
            host: host.to_string(),
            token: token.to_string(),
            repo_dir: repo_dir.to_owned(),
        }
    }

    pub fn run(&self, args: &[&str]) -> Result<String, String> {
        self.do_run(args, None)
    }

    pub fn run_with_stdin(&self, args: &[&str], stdin: &str) -> Result<String, String> {
        self.do_run(args, Some(stdin))
    }

    fn ask_pass_path(&self) -> String {
        let ask_pass = "octobot-ask-pass";
        match env::current_exe() {
            Ok(ref exe) if exe.parent().is_some() => {
                exe.parent().unwrap().join(ask_pass).to_string_lossy().into_owned()
            }
            _ => ask_pass.to_string(),
        }
    }

    pub fn has_branch(&self, branch: &str) -> Result<bool, String> {
        let output = try!(self.run(&["branch"]));
        // skip first two characters for the bullet point
        Ok(output.lines().any(|b| b.len() > 2 && branch == &b[2..]))
    }

    pub fn current_branch(&self) -> Result<String, String> {
        self.run(&["rev-parse", "--abbrev-ref", "HEAD"])
    }

    pub fn does_branch_contain(&self, git_ref: &str, branch: &str) -> Result<bool, String> {
        let output = try!(self.run(&["branch", "--contains", git_ref]));
        // return branches, stripping out the bullet point
        Ok(output.lines().any(|b| b.len() > 2 && branch == &b[2..]))
    }

    // Find the commit at which |leaf_ref| forked from |base_branch|.
    // This can find which commits belong to a PR.
    // Returns the ref found in the base branch that this git_ref came from.
    pub fn find_base_branch_commit(&self, leaf_ref: &str, base_branch: &str) -> Result<String, String> {
        self.run(&["merge-base", base_branch, leaf_ref])
    }

    pub fn clean(&self) -> Result<(), String> {
        try!(self.run(&["reset", "--hard"]));
        try!(self.run(&["clean", "-fdx"]));
        Ok(())
    }

    // checking a branch named |new_branch_name| and ensure it is up to date with |source_branch|
    // |source_branch| can be a commit hash or an origin/branch-name.
    pub fn checkout_branch(&self, new_branch_name: &str, source_branch: &str) ->  Result<(), String> {
        let current_branch = try!(self.current_branch());
        if current_branch == new_branch_name {
            try!(self.run(&["reset", "--hard", &source_branch]));
        } else {
            // delete if it exists
            let has_branch = try!(self.has_branch(new_branch_name));
            if has_branch {
                try!(self.run(&["branch", "-D", new_branch_name]));
            }
            // recreate branch
            try!(self.run(&["checkout", "-b", new_branch_name, &source_branch]));
        }

        Ok(())
    }

    pub fn diff(&self, base: &str, head: &str) -> Result<String, String> {
        self.run(&["diff", base, head, "-w"])
    }

    // returns (title, body)
    pub fn get_commit_desc(&self, commit_hash: &str) -> Result<(String, String), String> {
        let lines: Vec<String> = try!(self.run(&["log", "-1", "--pretty=%B", commit_hash]))
            .split("\n")
            .map(|l| l.trim().to_string())
            .collect();

        if lines.len() == 0 {
            return Err(format!("Empty commit message found!"));
        }

        let title = lines[0].clone();

        let mut body = String::new();
        // skip the blank line
        if lines.len() > 2 {
            body = lines[2..].join("\n");
            body += "\n";
        }

        Ok((title, body))
    }

    fn do_run(&self, args: &[&str], stdin: Option<&str>) -> Result<String, String> {
        debug!("Running git with args: {:?}", args);
        let cmd = Command::new("git")
            .current_dir(&self.repo_dir)
            .stdin(if stdin.is_some() {
                Stdio::piped()
            } else {
                Stdio::null()
            })
            .stderr(Stdio::piped())
            .stdout(Stdio::piped())
            .args(args)
            .env("GIT_ASKPASS", &self.ask_pass_path())
            .env("OCTOBOT_HOST", &self.host)
            .env("OCTOBOT_PASS", &self.token)
            .spawn();

        let mut child = match cmd {
            Ok(c) => c,
            Err(e) => return Err(format!("Error starting git: {}", e)),
        };

        if let Some(ref stdin) = stdin {
            if let Some(ref mut child_stdin) = child.stdin {
                if let Err(e) = child_stdin.write_all(stdin.as_bytes()) {
                    return Err(format!("Error writing to stdin: {}", e));
                }
            }
        }

        let result = match child.wait_with_output() {
            Ok(r) => r,
            Err(e) => return Err(format!("Error running git: {}", e)),
        };

        let mut output = String::new();
        if result.stdout.len() > 0 {
            output += String::from_utf8_lossy(&result.stdout).as_ref();
        }

        if !result.status.success() {
            if result.stderr.len() > 0 {
                output += String::from_utf8_lossy(&result.stderr).as_ref();
            }
            Err(format!("Error running git (exit code {}):\n{}",
                        result.status.code().unwrap_or(-1),
                        output))
        } else {

            Ok(output.trim().to_string())
        }
    }
}
<|endoftext|>


<commit_before>use format_buf::format;
use hir::InFile;
use join_to_string::join;
use ra_syntax::{
    ast::{
        self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner,
    },
    TextUnit, T,
};
use std::fmt::Write;

use crate::{Assist, AssistCtx, AssistId};

// Assist: add_new
//
// Adds a new inherent impl for a type.
//
// ```
// struct Ctx<T: Clone> {
//      data: T,<|>
// }
// ```
// ->
// ```
// struct Ctx<T: Clone> {
//      data: T,
// }
//
// impl<T: Clone> Ctx<T> {
//     fn new(data: T) -> Self { Self { data } }
// }
//
// ```
pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> {
    let strukt = ctx.find_node_at_offset::<ast::StructDef>()?;

    // We want to only apply this to non-union structs with named fields
    let field_list = match strukt.kind() {
        StructKind::Record(named) => named,
        _ => return None,
    };

    // Return early if we've found an existing new fn
    let impl_block = find_struct_impl(&ctx, &strukt)?;

    ctx.add_assist(AssistId("add_new"), "Add default constructor", |edit| {
        edit.target(strukt.syntax().text_range());

        let mut buf = String::with_capacity(512);

        if impl_block.is_some() {
            buf.push('\n');
        }

        let vis = strukt.visibility().map(|v| format!("{} ", v.syntax()));
        let vis = vis.as_ref().map(String::as_str).unwrap_or("");
        write!(&mut buf, "    {}fn new(", vis).unwrap();

        join(field_list.fields().filter_map(|f| {
            Some(format!("{}: {}", f.name()?.syntax().text(), f.ascribed_type()?.syntax().text()))
        }))
        .separator(", ")
        .to_buf(&mut buf);

        buf.push_str(") -> Self { Self {");

        join(field_list.fields().filter_map(|f| Some(f.name()?.syntax().text())))
            .separator(", ")
            .surround_with(" ", " ")
            .to_buf(&mut buf);

        buf.push_str("} }");

        let (start_offset, end_offset) = impl_block
            .and_then(|impl_block| {
                buf.push('\n');
                let start = impl_block
                    .syntax()
                    .descendants_with_tokens()
                    .find(|t| t.kind() == T!['{'])?
                    .text_range()
                    .end();

                Some((start, TextUnit::from_usize(1)))
            })
            .unwrap_or_else(|| {
                buf = generate_impl_text(&strukt, &buf);
                let start = strukt.syntax().text_range().end();

                (start, TextUnit::from_usize(3))
            });

        edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset);
        edit.insert(start_offset, buf);
    })
}

// Generates the surrounding `impl Type { <code> }` including type and lifetime
// parameters
fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
    let type_params = strukt.type_param_list();
    let mut buf = String::with_capacity(code.len());
    buf.push_str("\n\nimpl");
    if let Some(type_params) = &type_params {
        format!(buf, "{}", type_params.syntax());
    }
    buf.push_str(" ");
    buf.push_str(strukt.name().unwrap().text().as_str());
    if let Some(type_params) = type_params {
        let lifetime_params = type_params
            .lifetime_params()
            .filter_map(|it| it.lifetime_token())
            .map(|it| it.text().clone());
        let type_params =
            type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
        join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf);
    }

    format!(&mut buf, " {{\n{}\n}}\n", code);

    buf
}

// Uses a syntax-driven approach to find any impl blocks for the struct that
// exist within the module/file
//
// Returns `None` if we've found an existing `new` fn
//
// FIXME: change the new fn checking to a more semantic approach when that's more
// viable (e.g. we process proc macros, etc)
fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option<Option<ast::ImplBlock>> {
    let db = ctx.db;
    let module = strukt.syntax().ancestors().find(|node| {
        ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind())
    })?;
    let mut sb = ctx.source_binder();

    let struct_ty = {
        let src = InFile { file_id: ctx.frange.file_id.into(), value: strukt.clone() };
        sb.to_def(src)?.ty(db)
    };

    let block = module.descendants().filter_map(ast::ImplBlock::cast).find_map(|impl_blk| {
        let src = InFile { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() };
        let blk = sb.to_def(src)?;

        // TODO this check doesn't work
        let same_ty = blk.target_ty(db) == struct_ty;
        let not_trait_impl = blk.target_trait(db).is_none();

        if !(same_ty && not_trait_impl) {
            None
        } else {
            Some(impl_blk)
        }
    });

    if let Some(ref impl_blk) = block {
        if has_new_fn(impl_blk) {
            return None;
        }
    }

    Some(block)
}

fn has_new_fn(imp: &ast::ImplBlock) -> bool {
    if let Some(il) = imp.item_list() {
        for item in il.impl_items() {
            if let ast::ImplItem::FnDef(f) = item {
                if let Some(name) = f.name() {
                    if name.text().eq_ignore_ascii_case("new") {
                        return true;
                    }
                }
            }
        }
    }

    false
}

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

    use super::*;

    #[test]
    #[rustfmt::skip]
    fn test_add_new() {
        // Check output of generation
        check_assist(
            add_new,
"struct Foo {<|>}",
"struct Foo {}

impl Foo {
    fn new() -> Self { Self {  } }<|>
}
",
        );
        check_assist(
            add_new,
"struct Foo<T: Clone> {<|>}",
"struct Foo<T: Clone> {}

impl<T: Clone> Foo<T> {
    fn new() -> Self { Self {  } }<|>
}
",
        );
        check_assist(
            add_new,
"struct Foo<'a, T: Foo<'a>> {<|>}",
"struct Foo<'a, T: Foo<'a>> {}

impl<'a, T: Foo<'a>> Foo<'a, T> {
    fn new() -> Self { Self {  } }<|>
}
",
        );
        check_assist(
            add_new,
"struct Foo { baz: String <|>}",
"struct Foo { baz: String }

impl Foo {
    fn new(baz: String) -> Self { Self { baz } }<|>
}
",
        );
        check_assist(
            add_new,
"struct Foo { baz: String, qux: Vec<i32> <|>}",
"struct Foo { baz: String, qux: Vec<i32> }

impl Foo {
    fn new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }<|>
}
",
        );

        // Check that visibility modifiers don't get brought in for fields
        check_assist(
            add_new,
"struct Foo { pub baz: String, pub qux: Vec<i32> <|>}",
"struct Foo { pub baz: String, pub qux: Vec<i32> }

impl Foo {
    fn new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }<|>
}
",
        );

        // Check that it reuses existing impls
        check_assist(
            add_new,
"struct Foo {<|>}

impl Foo {}
",
"struct Foo {}

impl Foo {
    fn new() -> Self { Self {  } }<|>
}
",
        );
        check_assist(
            add_new,
"struct Foo {<|>}

impl Foo {
    fn qux(&self) {}
}
",
"struct Foo {}

impl Foo {
    fn new() -> Self { Self {  } }<|>

    fn qux(&self) {}
}
",
        );

        check_assist(
            add_new,
"struct Foo {<|>}

impl Foo {
    fn qux(&self) {}
    fn baz() -> i32 {
        5
    }
}
",
"struct Foo {}

impl Foo {
    fn new() -> Self { Self {  } }<|>

    fn qux(&self) {}
    fn baz() -> i32 {
        5
    }
}
",
        );

        // Check visibility of new fn based on struct
        check_assist(
            add_new,
"pub struct Foo {<|>}",
"pub struct Foo {}

impl Foo {
    pub fn new() -> Self { Self {  } }<|>
}
",
        );
        check_assist(
            add_new,
"pub(crate) struct Foo {<|>}",
"pub(crate) struct Foo {}

impl Foo {
    pub(crate) fn new() -> Self { Self {  } }<|>
}
",
        );
    }

    #[test]
    fn add_new_not_applicable_if_fn_exists() {
        check_assist_not_applicable(
            add_new,
            "
struct Foo {<|>}

impl Foo {
    fn new() -> Self {
        Self
    }
}",
        );

        check_assist_not_applicable(
            add_new,
            "
struct Foo {<|>}

impl Foo {
    fn New() -> Self {
        Self
    }
}",
        );
    }

    #[test]
    fn add_new_target() {
        check_assist_target(
            add_new,
            "
struct SomeThingIrrelevant;
/// Has a lifetime parameter
struct Foo<'a, T: Foo<'a>> {<|>}
struct EvenMoreIrrelevant;
",
            "/// Has a lifetime parameter
struct Foo<'a, T: Foo<'a>> {}",
        );
    }

    #[test]
    fn test_unrelated_new() {
        check_assist(
            add_new,
            r##"
pub struct AstId<N: AstNode> {
    file_id: HirFileId,
    file_ast_id: FileAstId<N>,
}

impl<N: AstNode> AstId<N> {
    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
        AstId { file_id, file_ast_id }
    }
}

pub struct Source<T> {
    pub file_id: HirFileId,<|>
    pub ast: T,
}

impl<T> Source<T> {
    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
        Source { file_id: self.file_id, ast: f(self.ast) }
    }
}
"##,
            r##"
pub struct AstId<N: AstNode> {
    file_id: HirFileId,
    file_ast_id: FileAstId<N>,
}

impl<N: AstNode> AstId<N> {
    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
        AstId { file_id, file_ast_id }
    }
}

pub struct Source<T> {
    pub file_id: HirFileId,
    pub ast: T,
}

impl<T> Source<T> {
    pub fn new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }<|>

    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
        Source { file_id: self.file_id, ast: f(self.ast) }
    }
}
"##,
        );
    }
}
<commit_msg>Fix add_new assist (kind of)<commit_after>use format_buf::format;
use hir::{Adt, InFile};
use join_to_string::join;
use ra_syntax::{
    ast::{
        self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner,
    },
    TextUnit, T,
};
use std::fmt::Write;

use crate::{Assist, AssistCtx, AssistId};

// Assist: add_new
//
// Adds a new inherent impl for a type.
//
// ```
// struct Ctx<T: Clone> {
//      data: T,<|>
// }
// ```
// ->
// ```
// struct Ctx<T: Clone> {
//      data: T,
// }
//
// impl<T: Clone> Ctx<T> {
//     fn new(data: T) -> Self { Self { data } }
// }
//
// ```
pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> {
    let strukt = ctx.find_node_at_offset::<ast::StructDef>()?;

    // We want to only apply this to non-union structs with named fields
    let field_list = match strukt.kind() {
        StructKind::Record(named) => named,
        _ => return None,
    };

    // Return early if we've found an existing new fn
    let impl_block = find_struct_impl(&ctx, &strukt)?;

    ctx.add_assist(AssistId("add_new"), "Add default constructor", |edit| {
        edit.target(strukt.syntax().text_range());

        let mut buf = String::with_capacity(512);

        if impl_block.is_some() {
            buf.push('\n');
        }

        let vis = strukt.visibility().map(|v| format!("{} ", v.syntax()));
        let vis = vis.as_ref().map(String::as_str).unwrap_or("");
        write!(&mut buf, "    {}fn new(", vis).unwrap();

        join(field_list.fields().filter_map(|f| {
            Some(format!("{}: {}", f.name()?.syntax().text(), f.ascribed_type()?.syntax().text()))
        }))
        .separator(", ")
        .to_buf(&mut buf);

        buf.push_str(") -> Self { Self {");

        join(field_list.fields().filter_map(|f| Some(f.name()?.syntax().text())))
            .separator(", ")
            .surround_with(" ", " ")
            .to_buf(&mut buf);

        buf.push_str("} }");

        let (start_offset, end_offset) = impl_block
            .and_then(|impl_block| {
                buf.push('\n');
                let start = impl_block
                    .syntax()
                    .descendants_with_tokens()
                    .find(|t| t.kind() == T!['{'])?
                    .text_range()
                    .end();

                Some((start, TextUnit::from_usize(1)))
            })
            .unwrap_or_else(|| {
                buf = generate_impl_text(&strukt, &buf);
                let start = strukt.syntax().text_range().end();

                (start, TextUnit::from_usize(3))
            });

        edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset);
        edit.insert(start_offset, buf);
    })
}

// Generates the surrounding `impl Type { <code> }` including type and lifetime
// parameters
fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
    let type_params = strukt.type_param_list();
    let mut buf = String::with_capacity(code.len());
    buf.push_str("\n\nimpl");
    if let Some(type_params) = &type_params {
        format!(buf, "{}", type_params.syntax());
    }
    buf.push_str(" ");
    buf.push_str(strukt.name().unwrap().text().as_str());
    if let Some(type_params) = type_params {
        let lifetime_params = type_params
            .lifetime_params()
            .filter_map(|it| it.lifetime_token())
            .map(|it| it.text().clone());
        let type_params =
            type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
        join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf);
    }

    format!(&mut buf, " {{\n{}\n}}\n", code);

    buf
}

// Uses a syntax-driven approach to find any impl blocks for the struct that
// exist within the module/file
//
// Returns `None` if we've found an existing `new` fn
//
// FIXME: change the new fn checking to a more semantic approach when that's more
// viable (e.g. we process proc macros, etc)
fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option<Option<ast::ImplBlock>> {
    let db = ctx.db;
    let module = strukt.syntax().ancestors().find(|node| {
        ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind())
    })?;
    let mut sb = ctx.source_binder();

    let struct_def = {
        let src = InFile { file_id: ctx.frange.file_id.into(), value: strukt.clone() };
        sb.to_def(src)?
    };

    let block = module.descendants().filter_map(ast::ImplBlock::cast).find_map(|impl_blk| {
        let src = InFile { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() };
        let blk = sb.to_def(src)?;

        // FIXME: handle e.g. `struct S<T>; impl<U> S<U> {}`
        // (we currently use the wrong type parameter)
        // also we wouldn't want to use e.g. `impl S<u32>`
        let same_ty = match blk.target_ty(db).as_adt() {
            Some(def) => def == Adt::Struct(struct_def),
            None => false,
        };
        let not_trait_impl = blk.target_trait(db).is_none();

        if !(same_ty && not_trait_impl) {
            None
        } else {
            Some(impl_blk)
        }
    });

    if let Some(ref impl_blk) = block {
        if has_new_fn(impl_blk) {
            return None;
        }
    }

    Some(block)
}

fn has_new_fn(imp: &ast::ImplBlock) -> bool {
    if let Some(il) = imp.item_list() {
        for item in il.impl_items() {
            if let ast::ImplItem::FnDef(f) = item {
                if let Some(name) = f.name() {
                    if name.text().eq_ignore_ascii_case("new") {
                        return true;
                    }
                }
            }
        }
    }

    false
}

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

    use super::*;

    #[test]
    #[rustfmt::skip]
    fn test_add_new() {
        // Check output of generation
        check_assist(
            add_new,
"struct Foo {<|>}",
"struct Foo {}

impl Foo {
    fn new() -> Self { Self {  } }<|>
}
",
        );
        check_assist(
            add_new,
"struct Foo<T: Clone> {<|>}",
"struct Foo<T: Clone> {}

impl<T: Clone> Foo<T> {
    fn new() -> Self { Self {  } }<|>
}
",
        );
        check_assist(
            add_new,
"struct Foo<'a, T: Foo<'a>> {<|>}",
"struct Foo<'a, T: Foo<'a>> {}

impl<'a, T: Foo<'a>> Foo<'a, T> {
    fn new() -> Self { Self {  } }<|>
}
",
        );
        check_assist(
            add_new,
"struct Foo { baz: String <|>}",
"struct Foo { baz: String }

impl Foo {
    fn new(baz: String) -> Self { Self { baz } }<|>
}
",
        );
        check_assist(
            add_new,
"struct Foo { baz: String, qux: Vec<i32> <|>}",
"struct Foo { baz: String, qux: Vec<i32> }

impl Foo {
    fn new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }<|>
}
",
        );

        // Check that visibility modifiers don't get brought in for fields
        check_assist(
            add_new,
"struct Foo { pub baz: String, pub qux: Vec<i32> <|>}",
"struct Foo { pub baz: String, pub qux: Vec<i32> }

impl Foo {
    fn new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }<|>
}
",
        );

        // Check that it reuses existing impls
        check_assist(
            add_new,
"struct Foo {<|>}

impl Foo {}
",
"struct Foo {}

impl Foo {
    fn new() -> Self { Self {  } }<|>
}
",
        );
        check_assist(
            add_new,
"struct Foo {<|>}

impl Foo {
    fn qux(&self) {}
}
",
"struct Foo {}

impl Foo {
    fn new() -> Self { Self {  } }<|>

    fn qux(&self) {}
}
",
        );

        check_assist(
            add_new,
"struct Foo {<|>}

impl Foo {
    fn qux(&self) {}
    fn baz() -> i32 {
        5
    }
}
",
"struct Foo {}

impl Foo {
    fn new() -> Self { Self {  } }<|>

    fn qux(&self) {}
    fn baz() -> i32 {
        5
    }
}
",
        );

        // Check visibility of new fn based on struct
        check_assist(
            add_new,
"pub struct Foo {<|>}",
"pub struct Foo {}

impl Foo {
    pub fn new() -> Self { Self {  } }<|>
}
",
        );
        check_assist(
            add_new,
"pub(crate) struct Foo {<|>}",
"pub(crate) struct Foo {}

impl Foo {
    pub(crate) fn new() -> Self { Self {  } }<|>
}
",
        );
    }

    #[test]
    fn add_new_not_applicable_if_fn_exists() {
        check_assist_not_applicable(
            add_new,
            "
struct Foo {<|>}

impl Foo {
    fn new() -> Self {
        Self
    }
}",
        );

        check_assist_not_applicable(
            add_new,
            "
struct Foo {<|>}

impl Foo {
    fn New() -> Self {
        Self
    }
}",
        );
    }

    #[test]
    fn add_new_target() {
        check_assist_target(
            add_new,
            "
struct SomeThingIrrelevant;
/// Has a lifetime parameter
struct Foo<'a, T: Foo<'a>> {<|>}
struct EvenMoreIrrelevant;
",
            "/// Has a lifetime parameter
struct Foo<'a, T: Foo<'a>> {}",
        );
    }

    #[test]
    fn test_unrelated_new() {
        check_assist(
            add_new,
            r##"
pub struct AstId<N: AstNode> {
    file_id: HirFileId,
    file_ast_id: FileAstId<N>,
}

impl<N: AstNode> AstId<N> {
    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
        AstId { file_id, file_ast_id }
    }
}

pub struct Source<T> {
    pub file_id: HirFileId,<|>
    pub ast: T,
}

impl<T> Source<T> {
    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
        Source { file_id: self.file_id, ast: f(self.ast) }
    }
}
"##,
            r##"
pub struct AstId<N: AstNode> {
    file_id: HirFileId,
    file_ast_id: FileAstId<N>,
}

impl<N: AstNode> AstId<N> {
    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
        AstId { file_id, file_ast_id }
    }
}

pub struct Source<T> {
    pub file_id: HirFileId,
    pub ast: T,
}

impl<T> Source<T> {
    pub fn new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }<|>

    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
        Source { file_id: self.file_id, ast: f(self.ast) }
    }
}
"##,
        );
    }
}
<|endoftext|>