fixes
rodzic
2c9cc73d6a
commit
1f2005fa07
|
@ -139,52 +139,6 @@ impl<T> List<T> where T: Sized + Clone {
|
||||||
.value
|
.value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Splits off and returns `n` nodes as a `List<T>`.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// `n: usize` - The number of elements after which to split the list.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics when:
|
|
||||||
/// - The list is empty
|
|
||||||
/// - `n` is larger than the length
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use testing::List;
|
|
||||||
///
|
|
||||||
/// let mut list = List::new_empty();
|
|
||||||
/// list.append(12);
|
|
||||||
/// list.append(11);
|
|
||||||
/// list.append(10);
|
|
||||||
/// let mut list2 = list.split(1);
|
|
||||||
/// assert_eq!(list2.pop(), Some(12));
|
|
||||||
/// assert_eq!(list.pop(), Some(11));
|
|
||||||
/// assert_eq!(list.pop(), Some(10));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn split(&mut self, n: usize) -> List<T> {
|
|
||||||
|
|
||||||
// Don't do this in real life. Use Results, Options, or anything that
|
|
||||||
// doesn't just kill the program
|
|
||||||
if self.length == 0 || n >= self.length - 1 {
|
|
||||||
panic!("That's not working");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut n = n;
|
|
||||||
let mut new_list = List::new_empty();
|
|
||||||
while n > 0 {
|
|
||||||
new_list.append(self.pop().unwrap());
|
|
||||||
n -= 1;
|
|
||||||
}
|
|
||||||
new_list
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T>Drop for List<T> where T: Clone + Sized {
|
impl <T>Drop for List<T> where T: Clone + Sized {
|
||||||
|
@ -248,25 +202,4 @@ mod tests {
|
||||||
assert_eq!(list.length, 0);
|
assert_eq!(list.length, 0);
|
||||||
assert_eq!(list.pop(), None);
|
assert_eq!(list.pop(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_list_split() {
|
|
||||||
let mut list = List::new_empty();
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
assert_eq!(list.length, 5);
|
|
||||||
let list2 = list.split(3);
|
|
||||||
assert_eq!(list.length, 2);
|
|
||||||
assert_eq!(list2.length, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn test_list_split_panics() {
|
|
||||||
let mut list: List<i32> = List::new_empty();
|
|
||||||
let _ = list.split(3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,22 @@
|
||||||
use std::io::{Write, Read};
|
use std::io::{Read, Write};
|
||||||
// Structs
|
// Structs
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Configuration for our application
|
/// Configuration for our application
|
||||||
///
|
///
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
values: Vec<(String, String)>
|
values: Vec<(String, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// A service for managing a configuration
|
/// A service for managing a configuration
|
||||||
///
|
///
|
||||||
pub struct KeyValueConfigService {
|
pub struct KeyValueConfigService {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Traits
|
// Traits
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Provides a get() function to return valuse associated with
|
/// Provides a get() function to return values associated with
|
||||||
/// the specified key.
|
/// the specified key.
|
||||||
///
|
///
|
||||||
pub trait ValueGetter {
|
pub trait ValueGetter {
|
||||||
|
@ -43,16 +41,13 @@ pub trait ConfigReader {
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn new(values: Vec<(String, String)>) -> Config {
|
pub fn new(values: Vec<(String, String)>) -> Config {
|
||||||
Config {
|
Config { values: values }
|
||||||
values: values
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyValueConfigService {
|
impl KeyValueConfigService {
|
||||||
pub fn new() -> KeyValueConfigService {
|
pub fn new() -> KeyValueConfigService {
|
||||||
KeyValueConfigService {
|
KeyValueConfigService {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,12 +69,13 @@ impl ConfigReader for KeyValueConfigService {
|
||||||
let values: Vec<(String, String)> = buffer
|
let values: Vec<(String, String)> = buffer
|
||||||
.split_terminator("\n") // split
|
.split_terminator("\n") // split
|
||||||
.map(|line| line.trim()) // remove whitespace
|
.map(|line| line.trim()) // remove whitespace
|
||||||
.filter(|line| { // filter invalid lines
|
.filter(|line| {
|
||||||
let pos = line.find("=")
|
// filter invalid lines
|
||||||
.unwrap_or(0);
|
let pos = line.find("=").unwrap_or(0);
|
||||||
pos > 0 && pos < line.len() - 1
|
pos > 0 && pos < line.len() - 1
|
||||||
})
|
})
|
||||||
.map(|line| { // create a tuple from a line
|
.map(|line| {
|
||||||
|
// create a tuple from a line
|
||||||
let parts = line.split("=").collect::<Vec<&str>>();
|
let parts = line.split("=").collect::<Vec<&str>>();
|
||||||
(parts[0].to_string(), parts[1].to_string())
|
(parts[0].to_string(), parts[1].to_string())
|
||||||
})
|
})
|
||||||
|
@ -90,16 +86,16 @@ impl ConfigReader for KeyValueConfigService {
|
||||||
|
|
||||||
impl ValueGetter for Config {
|
impl ValueGetter for Config {
|
||||||
fn get(&self, s: &str) -> Option<String> {
|
fn get(&self, s: &str) -> Option<String> {
|
||||||
self.values.iter()
|
self.values.iter().find_map(|tuple| {
|
||||||
.find_map(|tuple| if &tuple.0 == s {
|
if &tuple.0 == s {
|
||||||
Some(tuple.1.clone())
|
Some(tuple.1.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -112,7 +108,6 @@ mod tests {
|
||||||
assert_eq!(config.get("HELLO"), None);
|
assert_eq!(config.get("HELLO"), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn keyvalueconfigservice_write_config() {
|
fn keyvalueconfigservice_write_config() {
|
||||||
let config = Config::new(vec![("hello".to_string(), "world".to_string())]);
|
let config = Config::new(vec![("hello".to_string(), "world".to_string())]);
|
||||||
|
@ -121,20 +116,27 @@ mod tests {
|
||||||
let mut target = vec![];
|
let mut target = vec![];
|
||||||
assert!(service.write(config, &mut target).is_ok());
|
assert!(service.write(config, &mut target).is_ok());
|
||||||
|
|
||||||
assert_eq!(String::from_utf8(target).unwrap(), "hello=world\n".to_string());
|
assert_eq!(
|
||||||
|
String::from_utf8(target).unwrap(),
|
||||||
|
"hello=world\n".to_string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn keyvalueconfigservice_read_config() {
|
fn keyvalueconfigservice_read_config() {
|
||||||
|
|
||||||
let service = KeyValueConfigService::new();
|
let service = KeyValueConfigService::new();
|
||||||
let readable = &format!("{}\n{}", "hello=world", "a=b").into_bytes();
|
let readable = &format!("{}\n{}", "hello=world", "a=b").into_bytes();
|
||||||
|
|
||||||
let config = service.read(&mut Cursor::new(readable))
|
let config = service
|
||||||
|
.read(&mut Cursor::new(readable))
|
||||||
.expect("Couldn't read from the vector");
|
.expect("Couldn't read from the vector");
|
||||||
|
|
||||||
assert_eq!(config.values, vec![
|
assert_eq!(
|
||||||
|
config.values,
|
||||||
|
vec![
|
||||||
("hello".to_string(), "world".to_string()),
|
("hello".to_string(), "world".to_string()),
|
||||||
("a".to_string(), "b".to_string())]);
|
("a".to_string(), "b".to_string())
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
|
||||||
//pub mod list;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
|
@ -1,261 +0,0 @@
|
||||||
//!
|
|
||||||
//! A simple singly-linked list for the Rust-Cookbook by Packt Publishing.
|
|
||||||
//!
|
|
||||||
//! Recipes covered in this module:
|
|
||||||
//! - Documenting your code
|
|
||||||
//! - Testing your documentation
|
|
||||||
//! - Writing tests and benchmarks
|
|
||||||
//!
|
|
||||||
|
|
||||||
|
|
||||||
#![doc(html_logo_url = "https://blog.x5ff.xyz/img/main/logo.png",
|
|
||||||
test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
type Link<T> = Option<Rc<RefCell<Node<T>>>>;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct Node<T> where T: Sized + Clone {
|
|
||||||
value: T,
|
|
||||||
next: Link<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl<T> Node<T> where T: Sized + Clone {
|
|
||||||
fn new(value: T) -> Rc<RefCell<Node<T>>> {
|
|
||||||
Rc::new(RefCell::new(Node {
|
|
||||||
value: value,
|
|
||||||
next: None,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// A singly-linked list, with nodes allocated on the heap using `Rc`s and `RefCell`s. Here's an image illustrating a linked list:
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// 
|
|
||||||
///
|
|
||||||
/// *Found on https://en.wikipedia.org/wiki/Linked_list*
|
|
||||||
///
|
|
||||||
/// # Usage
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// let list = List::new_empty();
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct List<T> where T: Sized + Clone {
|
|
||||||
head: Link<T>,
|
|
||||||
tail: Link<T>,
|
|
||||||
|
|
||||||
///
|
|
||||||
/// The length of the list.
|
|
||||||
///
|
|
||||||
pub length: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> List<T> where T: Sized + Clone {
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Creates a new empty list.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use mut_sharing_ownership::list::List;
|
|
||||||
/// let list: List<i32> = List::new_empty();
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn new_empty() -> List<T> {
|
|
||||||
List { head: None, tail: None, length: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Appends a node to the list at the end.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// This never panics (probably).
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// No unsafe code was used.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use mut_sharing_ownership::list::List;
|
|
||||||
///
|
|
||||||
/// let mut list = List::new_empty();
|
|
||||||
/// list.append(10);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn append(&mut self, value: T) {
|
|
||||||
let new = Node::new(value);
|
|
||||||
match self.tail.take() {
|
|
||||||
Some(old) => old.borrow_mut().next = Some(new.clone()),
|
|
||||||
None => self.head = Some(new.clone())
|
|
||||||
};
|
|
||||||
self.length += 1;
|
|
||||||
self.tail = Some(new);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Removes the list's head and returns the result.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Whenever when a node unexpectedly is `None`
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use mut_sharing_ownership::list::List;
|
|
||||||
///
|
|
||||||
/// let mut list = List::new_empty();
|
|
||||||
/// list.append(10);
|
|
||||||
/// assert_eq!(list.pop(), Some(10));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn pop(&mut self) -> Option<T> {
|
|
||||||
self.head.take().map(|head| {
|
|
||||||
if let Some(next) = head.borrow_mut().next.take() {
|
|
||||||
self.head = Some(next);
|
|
||||||
} else {
|
|
||||||
self.tail.take();
|
|
||||||
}
|
|
||||||
self.length -= 1;
|
|
||||||
Rc::try_unwrap(head)
|
|
||||||
.ok()
|
|
||||||
.expect("Something is terribly wrong")
|
|
||||||
.into_inner()
|
|
||||||
.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Splits off and returns `n` nodes as a `List<T>`.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// `n: usize` - The number of elements after which to split the list.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics when:
|
|
||||||
/// - The list is empty
|
|
||||||
/// - `n` is larger than the length
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use mut_sharing_ownership::list::List;
|
|
||||||
///
|
|
||||||
/// let mut list = List::new_empty();
|
|
||||||
/// list.append(12);
|
|
||||||
/// list.append(11);
|
|
||||||
/// list.append(10);
|
|
||||||
/// let mut list2 = list.split(1);
|
|
||||||
/// assert_eq!(list2.pop(), Some(12));
|
|
||||||
/// assert_eq!(list.pop(), Some(11));
|
|
||||||
/// assert_eq!(list.pop(), Some(10));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub fn split(&mut self, n: usize) -> List<T> {
|
|
||||||
|
|
||||||
// Don't do this in real life. Use Results, Options, or anything that
|
|
||||||
// doesn't just kill the program
|
|
||||||
if self.length == 0 || n >= self.length - 1 {
|
|
||||||
panic!("That's not working");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut n = n;
|
|
||||||
let mut new_list = List::new_empty();
|
|
||||||
while n > 0 {
|
|
||||||
new_list.append(self.pop().unwrap());
|
|
||||||
n -= 1;
|
|
||||||
}
|
|
||||||
new_list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <T>Drop for List<T> where T: Clone + Sized {
|
|
||||||
|
|
||||||
fn drop(&mut self) {
|
|
||||||
while self.length > 0 {
|
|
||||||
let n = self.pop();
|
|
||||||
drop(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_list_new_empty() {
|
|
||||||
let mut list: List<i32> = List::new_empty();
|
|
||||||
assert_eq!(list.length, 0);
|
|
||||||
assert_eq!(list.pop(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_list_append() {
|
|
||||||
let mut list = List::new_empty();
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
assert_eq!(list.length, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_list_pop() {
|
|
||||||
let mut list = List::new_empty();
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
assert_eq!(list.length, 5);
|
|
||||||
assert_eq!(list.pop(), Some(1));
|
|
||||||
assert_eq!(list.pop(), Some(1));
|
|
||||||
assert_eq!(list.pop(), Some(1));
|
|
||||||
assert_eq!(list.pop(), Some(1));
|
|
||||||
assert_eq!(list.pop(), Some(1));
|
|
||||||
assert_eq!(list.length, 0);
|
|
||||||
assert_eq!(list.pop(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_list_split() {
|
|
||||||
let mut list = List::new_empty();
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
list.append(1);
|
|
||||||
assert_eq!(list.length, 5);
|
|
||||||
let list2 = list.split(3);
|
|
||||||
assert_eq!(list.length, 2);
|
|
||||||
assert_eq!(list2.length, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn test_list_split_panics() {
|
|
||||||
let mut list: List<i32> = List::new_empty();
|
|
||||||
let _ = list.split(3);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,3 @@
|
||||||
extern crate tch;
|
|
||||||
use std::io::{Error, ErrorKind};
|
use std::io::{Error, ErrorKind};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
@ -118,14 +117,18 @@ fn predict_from_best() -> failure::Fallible<()> {
|
||||||
let net = ConvNet::new(&vs.root(), 10);
|
let net = ConvNet::new(&vs.root(), 10);
|
||||||
|
|
||||||
// restore weights
|
// restore weights
|
||||||
println!("Loading model weights from '{}'", model_weights_path.to_string_lossy());
|
println!(
|
||||||
|
"Loading model weights from '{}'",
|
||||||
|
model_weights_path.to_string_lossy()
|
||||||
|
);
|
||||||
vs.load(model_weights_path)?;
|
vs.load(model_weights_path)?;
|
||||||
|
|
||||||
println!("Probabilities and predictions for 10 random images in the test set");
|
println!("Probabilities and predictions for 10 random images in the test set");
|
||||||
for (image_batch, label_batch) in m.test_iter(1).shuffle().to_device(vs.device()).take(10) {
|
for (image_batch, label_batch) in m.test_iter(1).shuffle().to_device(vs.device()).take(10) {
|
||||||
let raw_tensor = net
|
let raw_tensor = net
|
||||||
.forward_t(&image_batch, false)
|
.forward_t(&image_batch, false)
|
||||||
.softmax(-1).view(m.labels);
|
.softmax(-1)
|
||||||
|
.view(m.labels);
|
||||||
let predicted_index: Vec<i64> = raw_tensor.argmax(0, false).into();
|
let predicted_index: Vec<i64> = raw_tensor.argmax(0, false).into();
|
||||||
let probabilities: Vec<f64> = raw_tensor.into();
|
let probabilities: Vec<f64> = raw_tensor.into();
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue