I am making small program for validating and computing IPs.
I wanted to try out modules and I encountered an error I do not know how to solve and can't find anything on the internet.
Here is my project structure:
src/
ip.rs
main.rs
mask.rs
show.rs
ip.rs
pub struct Ip {
pub first: u8,
pub second: u8,
pub third: u8,
pub forth: u8,
pub bin: [bool; 32]
}
pub fn build_ip(ip: String) -> Ip {
let split = ip.replace(".", ":");
let split = split.split(":");
let split_vec = split.collect::<Vec<&str>>();
let mut bin: [bool; 32] = [false; 32];
let mut octets: [u8; 4] = [0; 4];
if split_vec.len() != 4 {
panic!("Wrong amount of octets!");
}
for i in 0..4 {
let octet: u8 = match split_vec[i].trim().parse() {
Ok(num) => num,
Err(_) => panic!("Something wrong with first octet"),
};
octets[i] = octet;
let soctet = format!("{:b}", octet);
for (j, c) in soctet.chars().enumerate() {
bin[j + i*8] = c == '1';
}
}
Ip {
first: octets[0],
second: octets[1],
third: octets[2],
forth: octets[3],
bin: bin
}
}
show.rs
#[path = "ip.rs"] mod ip;
#[path = "mask.rs"] mod mask;
pub use ip::Ip;
pub fn print(name: String, ip: ip::Ip) {
println!("{}: ", name);
println!("{}.{}.{}.{}", ip.first, ip.second, ip.third, ip.forth);
for c in ip.bin.iter() {
print!("{}", *c as i32);
}
println!("");
println!("");
}
main.rs
pub mod mask;
pub mod ip;
pub mod show;
fn main() {
let ip = ip::build_ip("255:255:25:8:0".to_string());
// let mask = mask::build_mask("255.255.255.252".to_string());
show::print("ip".to_string(), ip)
}
When I try to compile it throws this at me and I have no idea what to do:
--> src\main.rs:9:32
|
9 | show::print("ip".to_string(), ip)
| ^^ expected struct `show::ip::Ip`, found struct `ip::Ip`
#[path = "ip.rs"] mod ip;
#[path = "mask.rs"] mod mask;
This declares new submodules, independent from the ones declared in mod.rs. That they have the same source code is immaterial, as far as typechecking and object identity are concerned they're completely unrelated.
Essentially, you've defined the following structure:
pub mod mask { ... }
pub mod ip {
pub struct Ip { ... }
pub fn build_ip(ip: String) -> Ip { ... }
}
pub mod show {
mod ip {
pub struct Ip { ... }
pub fn build_ip(ip: String) -> Ip { ... }
}
mod mask { ... }
pub fn print(name: String, ip: ip::Ip) { ... }
}
If you want to import modules, you should use use. If you need to import sibling modules, you can use the crate:: segment (in order to start resolving from the current crate's root), or super:: (to move up a level from the current module).
So here show should contain either use crate::{ip, mask} or use super::{ip, crate} in order to "see" its siblings.
The pub for use ip::Ip; is also completely unnecessary, you only needed it because you were declaring a new ip module, and thus needed its Ip to be public since you were using it in a pub function.
In show.rs, you write add the modules ip and mask, but these are already added in main.rs.
Instead, in show.rs use something like the following:
use crate::ip::Ip;
pub fn print(name: String, ip: Ip) {
...
}
Related
I've been trying to implement a Strategy pattern in rust, but I'm having trouble understanding how to make it work.
So let's imagine we have a trait Adder and Element:
pub trait Element {
fn to_string(&self) -> String;
}
pub trait Adder {
type E: Element;
fn add (&self, a: &Self::E, b: &Self::E) -> Self::E;
}
And we have two implementations StringAdder with StringElements and UsizeAdder with UsizeElements:
// usize
pub struct UsizeElement {
pub value: usize
}
impl Element for UsizeElement {
fn to_string(&self) -> String {
self.value.to_string()
}
}
pub struct UsizeAdder {
}
impl Adder for UsizeAdder{
type E = UsizeElement;
fn add(&self, a: &UsizeElement, b: &UsizeElement) -> UsizeElement{
UsizeElement { value: a.value + b.value }
}
}
// String
pub struct StringElement {
pub value: String
}
impl Element for StringElement {
fn to_string(&self) -> String {
self.value.to_string()
}
}
pub struct StringAdder {
}
impl Adder for StringAdder {
type E = StringElement;
fn add(&self, a: &StringElement, b: &StringElement) -> StringElement {
let a: usize = a.value.parse().unwrap();
let b: usize = b.value.parse().unwrap();
StringElement {
value: (a + b).to_string()
}
}
}
And I want to write a code that uses trait methods from Adder trait and it's corresponding elements without knowing at compile time which strategy is going to be used.
fn main() {
let policy = "usize";
let element = "1";
let adder = get_adder(&policy);
let element_a = get_element(&policy, element);
let result = adder.add(element_a, element_a);
}
To simplify I'm going to assign a string to policy and element but normally that would be read from a file.
Is the only way to implement get_adder and get_element using dynamic dispatch? And by extension should I define Adder and Element traits to use trait objects and or the Any trait?
Edit: Here is what I managed to figure out so far.
An example of possible implementation is using match to help define concrete types for the compiler.
fn main() {
let policy = "string";
let element = "1";
let secret_key = "5";
let result = cesar(policy, element, secret_key);
dbg!(result.to_string());
}
fn cesar(policy: &str, element: &str, secret_key: &str) -> Box<dyn Element>{
match policy {
"usize" => {
let adder = UsizeAdder{};
let element = UsizeElement{ value: element.parse().unwrap() };
let secret_key = UsizeElement{ value: secret_key.parse().unwrap() };
Box::new(cesar_impl(&adder, &element, &secret_key))
}
"string" => {
let adder = StringAdder{};
let element = StringElement{ value: element.to_string() };
let secret_key = StringElement{ value: secret_key.to_string() };
Box::new(cesar_impl(&adder, &element, &secret_key))
}
_ => {
panic!("Policy not supported!")
}
}
}
fn cesar_impl<A>(adder: &A, element: &A::E, secret_key: &A::E) -> A::E where A: Adder, A::E : Element {
adder.add(&element, &secret_key)
}
However the issue is that I have to wrap every function I want to implement using a match function to determine the concrete type, and also case for every policy available.
It does not seem like the proper way of implementing it as it will bloat the code, make it more error prone and less maintainable unless I end up using macros.
Edit 2: Here you can find an example using dynamic dispatch. However I'm not convinced it's the proper way to implement the solution.
Example using dynamic dispatch
Thank you for your help :)
Is there a readily available way to convert ip addresses (both v4 and v6) from binary to text form in Rust (an equivalent to inet_ntop)?
Examples:
"3701A8C0" converts to "55.1.168.192",
"20010db8000000000000000000000001" converts to "2001:db8::1".
inet_ntop takes as input a struct in_addr* or a struct in6_addr*. The direct equivalent of those structs in Rust are Ipv4Addr and Ipv6Addr, both of which implement the Display trait and can therefore be formatted easily to text or printed:
let addr = Ipv4Addr::from (0x3701A8C0);
assert_eq!(format!("{}", addr), String::from ("55.1.168.192"));
println!("{}", addr);
AFAIK, there is not a direct conversion, but you can do that with from_str_radix, and then with the conversion of an ip from a numeric type:
use std::{
error::Error,
io,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
str::FromStr,
};
fn convert(s: &str) -> io::Result<IpAddr> {
if let Ok(u) = u32::from_str_radix(s, 16) {
Ok(Ipv4Addr::from(u).into())
} else if let Ok(u) = u128::from_str_radix(s, 16) {
Ok(Ipv6Addr::from(u).into())
} else {
Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid input"))
}
}
fn main() -> Result<(), Box<dyn Error>> {
let ip = convert("3701A8C0")?;
assert_eq!(ip, IpAddr::from_str("55.1.168.192")?);
let ip = convert("20010db8000000000000000000000001")?;
assert_eq!(ip, IpAddr::from_str("2001:db8::1")?);
Ok(())
}
If you already know that it is, for example, and IPV4, this is a one-liner:
use std::{
error::Error,
net::{IpAddr, Ipv4Addr},
str::FromStr,
};
fn main() -> Result<(), Box<dyn Error>> {
let ip = u32::from_str_radix("3701A8C0", 16).map(Ipv4Addr::from)?;
assert_eq!(ip, IpAddr::from_str("55.1.168.192")?);
Ok(())
}
I am trying to create a network of nodes in Rust, where I want every node in the network to be aware of every other connected node. I thought that this could be done with weak Rc's, like this:
use std::cell::Cell;
use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;
struct Node {
name: String,
known_nodes: Rc<RefCell<Vec<Weak<Node>>>>,
}
impl Node {
fn connect_to_network(&mut self) {
self.known_nodes
.borrow_mut()
.push(Rc::downgrade(&Rc::new(*self)));
}
}
fn main() {
let known_nodes = Rc::new(RefCell::new(Vec::new()));
let node_one = Node {
name: "node1",
known_nodes: known_nodes.copy(),
};
node_one.connect_to_network();
let node_two = Node {
name: "node2",
known_nodes: known_nodes.copy(),
};
node_two.connect_to_network();
}
This however yields
cannot move out of borrowed content
at:
self.known_senders.borrow_mut().push(Rc::downgrade(&Rc::new(*self)));
Because *self is moved out of borrowed content in the &Rc::new(*self).
Any ideas, on how each node can keep track of all the other nodes in the network?
You should separate your node and your network, because your network must take the ownership of your node to create an Rc (or at least, it must take an already created Rc). Here is a better design that achieves what you want:
use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
name: String,
}
#[derive(Default, Debug)]
struct Network {
nodes: Rc<RefCell<Vec<Weak<Node>>>>,
}
impl Network {
fn add_node(&mut self, node: Node) -> Rc<Node> {
let node = Rc::new(node);
self.nodes.borrow_mut().push(Rc::downgrade(&node));
node
}
}
fn main() {
let mut network = Network::default();
let node_1 = Node { name: "node_1".into() };
let node_2 = Node { name: "node_2".into() };
let _node_1 = network.add_node(node_1);
let _node_2 = network.add_node(node_2);
}
If you want to store a reference to self, you can do this:
use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;
type MutableNode = Rc<RefCell<Node>>;
type Network = Rc<RefCell<Vec<Weak<RefCell<Node>>>>>;
struct Node {
name: String,
others: Network,
}
impl Node {
fn new(name: String) -> MutableNode {
let node = Rc::new(RefCell::new(Node {
name,
others: Rc::new(RefCell::new(Vec::new())),
}));
{
let tmp = node.borrow();
tmp.others.borrow_mut().push(Rc::downgrade(&node));
}
node
}
fn add_node(&mut self, name: String) -> MutableNode {
let others = self.others.clone();
let node = Rc::new(RefCell::new(Node { name, others }));
self.others
.borrow_mut()
.push(Rc::downgrade(&node));
node
}
fn len(&self) -> usize {
self.others.borrow().len()
}
}
fn main() {
let node_0 = Node::new("node_0".into());
let node_1 = node_0.borrow_mut().add_node("node_1".into());
let node_2 = node_0.borrow_mut().add_node("node_2".into());
assert_eq!(node_0.borrow().len(), 3);
assert_eq!(node_1.borrow().len(), 3);
assert_eq!(node_2.borrow().len(), 3);
}
Rc::new(value:T) consume the value.Your function only borrow it, so you can't call Rc::new(*self)
I would recommend you to create a Network struct like the above answer. Or you can wrap your node in Rc<RefCell<Node>> like this:
use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;
#[derive(Debug)]
struct Node {
name: String,
known_nodes: Rc<RefCell<Vec<Weak<RefCell<Node>>>>>,
}
impl Node {
fn connect_to_network(&mut self,ref_to_self: Weak<RefCell<Node>>) {
self.known_nodes
.borrow_mut()
.push(ref_to_self);
}
}
fn main() {
let known_nodes = Rc::new(RefCell::new(Vec::new()));
let node_one = Rc::new(RefCell::new(Node {
name: "node1".into(),
known_nodes: known_nodes.clone(),
}));
node_one.borrow_mut().connect_to_network(Rc::downgrade(&node_one));
let node_two = Rc::new(RefCell::new(Node {
name: "node2".into(),
known_nodes: known_nodes.clone(),
}));
node_two.borrow_mut().connect_to_network(Rc::downgrade(&node_two));
println!("{:?}",known_nodes.borrow()[0].upgrade());
println!("{:?}",known_nodes.borrow()[1].upgrade());
drop(node_one);
drop(node_two);
println!("{:?}",known_nodes.borrow()[0].upgrade());
println!("{:?}",known_nodes.borrow()[1].upgrade());
}
Which in this case you don't really need connect_to_network function, you can just add each Weak<RefCell<Node>> to known_nodes directly
If you want the code to look cleaner, you can introduce a new type alias to Rc<RefCell<Node>> like this
struct Node {
name: String,
known_nodes: Rc<RefCell<Vec<Weak<RefCell<Node>>>>>,
}
type RcNode = Rc<RefCell<Node>>;
trait Connectable {
fn connect_to_network(&self);
}
impl Connectable for RcNode {
fn connect_to_network(&self){
let node = self.borrow_mut();
node.known_nodes.borrow_mut().push(Rc::downgrade(self));
}
}
so then you can call
let node_one:RcNode = Rc::new(RefCell::new(Node {
name: "node1".into(),
known_nodes: known_nodes.clone(),
}));
node_one.connect_to_network();
In the past this code compiled, but recently it no longer is accepted (I believe since RFC 738). I want to type-parameterize the VertexBuffer, but it doesn't actually hold any vertices, rather the GPU holds the vertices, and the struct only holds an OpenGL buffer_id:
pub struct VertexBuffer<V: Vertex> {
buffer_id: GLuint,
num_vertices: usize,
}
The new function fills the buffer:
impl<V: Vertex> VertexBuffer<V> {
pub fn new(data: &Vec<V>) -> VertexBuffer<V>
{
let buffer_id = unsafe {
let mut id: GLuint = 0;
gl::GenBuffers(1, &mut id);
gl::BindBuffer(gl::ARRAY_BUFFER, id);
gl::BufferData(gl::ARRAY_BUFFER,
(mem::size_of::<V>() * data.len()) as GLsizeiptr,
mem::transmute(&data[0]),
gl::STATIC_DRAW);
id
};
VertexBuffer {
buffer_id: buffer_id,
num_vertices: data.len(),
}
}
....
}
I now get these errors:
src/vertex_buffer.rs:10:25: 10:26 error: parameter `V` is never used
src/vertex_buffer.rs:10 pub struct VertexBuffer<V: Vertex> {
src/vertex_buffer.rs:10:25: 10:26 help: consider removing `V` or using a marker such as `core::marker::PhantomData`
src/vertex_buffer.rs:10 pub struct VertexBuffer<V: Vertex> {
FYI, other functions in the impl such as pre_render() and post_render() use the V type to do their work, calling things like
let attribute_data = Vertex::attribute_data(None::<V>);
You haven't shown enough code to rule this out, so I'd suggest moving your type to the function(s):
impl VertexBuffer {
pub fn new<V: Vertex>(data: &Vec<V>) -> VertexBuffer<V> {
let buffer_id = unsafe {
let mut id: GLuint = 0;
gl::GenBuffers(1, &mut id);
gl::BindBuffer(gl::ARRAY_BUFFER, id);
gl::BufferData(gl::ARRAY_BUFFER,
(mem::size_of::<V>() * data.len()) as GLsizeiptr,
mem::transmute(&data[0]),
gl::STATIC_DRAW);
id
};
VertexBuffer {
buffer_id: buffer_id,
num_vertices: data.len(),
}
}
....
}
If you do need to use PhantomData, try something like:
struct VertexBuffer<V> {
buffer_id: u32, // or whatever
num_vertices: u32, // or whatever
marker: std::marker::PhantomData<V>,
}
impl<V: Vertex> VertexBuffer<V> {
pub fn new(data: &Vec<V>) -> VertexBuffer<V> {
let buffer_id = unsafe {
let mut id: GLuint = 0;
gl::GenBuffers(1, &mut id);
gl::BindBuffer(gl::ARRAY_BUFFER, id);
gl::BufferData(gl::ARRAY_BUFFER,
(mem::size_of::<V>() * data.len()) as GLsizeiptr,
mem::transmute(&data[0]),
gl::STATIC_DRAW);
id
};
VertexBuffer {
buffer_id: buffer_id,
num_vertices: data.len(),
marker: std::marker::PhantomData,
}
}
....
}
Say we want to have objects implementations switched at runtime, we'd do something like this:
pub trait Methods {
fn func(&self);
}
pub struct Methods_0;
impl Methods for Methods_0 {
fn func(&self) {
println!("foo");
}
}
pub struct Methods_1;
impl Methods for Methods_1 {
fn func(&self) {
println!("bar");
}
}
pub struct Object<'a> { //'
methods: &'a (Methods + 'a),
}
fn main() {
let methods: [&Methods; 2] = [&Methods_0, &Methods_1];
let mut obj = Object { methods: methods[0] };
obj.methods.func();
obj.methods = methods[1];
obj.methods.func();
}
Now, what if there are hundreds of such implementations? E.g. imagine implementations of cards for collectible card game where every card does something completely different and is hard to generalize; or imagine implementations for opcodes for a huge state machine. Sure you can argue that a different design pattern can be used -- but that's not the point of this question...
Wonder if there is any way for these Impl structs to somehow "register" themselves so they can be looked up later by a factory method? I would be happy to end up with a magical macro or even a plugin to accomplish that.
Say, in D you can use templates to register the implementations -- and if you can't for some reason, you can always inspect modules at compile-time and generate new code via mixins; there are also user-defined attributes that can help in this. In Python, you would normally use a metaclass so that every time a new child class is created, a ref to it is stored in the metaclass's registry which allows you to look up implementations by name or parameter; this can also be done via decorators if implementations are simple functions.
Ideally, in the example above you would be able to create Object as
Object::new(0)
where the value 0 is only known at runtime and it would magically return you an Object { methods: &Methods_0 }, and the body of new() would not have the implementations hard-coded like so "methods: [&Methods; 2] = [&Methods_0, &Methods_1]", instead it should be somehow inferred automatically.
So, this is probably extremely buggy, but it works as a proof of concept.
It is possible to use Cargo's code generation support to make the introspection at compile-time, by parsing (not exactly parsing in this case, but you get the idea) the present implementations, and generating the boilerplate necessary to make Object::new() work.
The code is pretty convoluted and has no error handling whatsoever, but works.
Tested on rustc 1.0.0-dev (2c0535421 2015-02-05 15:22:48 +0000)
(See on github)
src/main.rs:
pub mod implementations;
mod generated_glue {
include!(concat!(env!("OUT_DIR"), "/generated_glue.rs"));
}
use generated_glue::Object;
pub trait Methods {
fn func(&self);
}
pub struct Methods_2;
impl Methods for Methods_2 {
fn func(&self) {
println!("baz");
}
}
fn main() {
Object::new(2).func();
}
src/implementations.rs:
use super::Methods;
pub struct Methods_0;
impl Methods for Methods_0 {
fn func(&self) {
println!("foo");
}
}
pub struct Methods_1;
impl Methods for Methods_1 {
fn func(&self) {
println!("bar");
}
}
build.rs:
#![feature(core, unicode, path, io, env)]
use std::env;
use std::old_io::{fs, File, BufferedReader};
use std::collections::HashMap;
fn main() {
let target_dir = Path::new(env::var_string("OUT_DIR").unwrap());
let mut target_file = File::create(&target_dir.join("generated_glue.rs")).unwrap();
let source_code_path = Path::new(file!()).join_many(&["..", "src/"]);
let source_files = fs::readdir(&source_code_path).unwrap().into_iter()
.filter(|path| {
match path.str_components().last() {
Some(Some(filename)) => filename.split('.').last() == Some("rs"),
_ => false
}
});
let mut implementations = HashMap::new();
for source_file_path in source_files {
let relative_path = source_file_path.path_relative_from(&source_code_path).unwrap();
let source_file_name = relative_path.as_str().unwrap();
implementations.insert(source_file_name.to_string(), vec![]);
let mut file_implementations = &mut implementations[*source_file_name];
let mut source_file = BufferedReader::new(File::open(&source_file_path).unwrap());
for line in source_file.lines() {
let line_str = match line {
Ok(line_str) => line_str,
Err(_) => break,
};
if line_str.starts_with("impl Methods for Methods_") {
const PREFIX_LEN: usize = 25;
let number_len = line_str[PREFIX_LEN..].chars().take_while(|chr| {
chr.is_digit(10)
}).count();
let number: i32 = line_str[PREFIX_LEN..(PREFIX_LEN + number_len)].parse().unwrap();
file_implementations.push(number);
}
}
}
writeln!(&mut target_file, "use super::Methods;").unwrap();
for (source_file_name, impls) in &implementations {
let module_name = match source_file_name.split('.').next() {
Some("main") => "super",
Some(name) => name,
None => panic!(),
};
for impl_number in impls {
writeln!(&mut target_file, "use {}::Methods_{};", module_name, impl_number).unwrap();
}
}
let all_impls = implementations.values().flat_map(|impls| impls.iter());
writeln!(&mut target_file, "
pub struct Object;
impl Object {{
pub fn new(impl_number: i32) -> Box<Methods + 'static> {{
match impl_number {{
").unwrap();
for impl_number in all_impls {
writeln!(&mut target_file,
" {} => Box::new(Methods_{}),", impl_number, impl_number).unwrap();
}
writeln!(&mut target_file, "
_ => panic!(\"Unknown impl number: {{}}\", impl_number),
}}
}}
}}").unwrap();
}
The generated code:
use super::Methods;
use super::Methods_2;
use implementations::Methods_0;
use implementations::Methods_1;
pub struct Object;
impl Object {
pub fn new(impl_number: i32) -> Box<Methods + 'static> {
match impl_number {
2 => Box::new(Methods_2),
0 => Box::new(Methods_0),
1 => Box::new(Methods_1),
_ => panic!("Unknown impl number: {}", impl_number),
}
}
}