Copy content of fields from one public struct to another - rust
I'm working on modifying some code that was written by another party. The purpose is to emulate a UniFi Security Gateway to get reporting in the UniFi Controller software. I'm planning to run the emulation on a Zotac Mini PC with 2 NICs running CentOS 8. So that I don't have to worry about additional NAT, I have the 2 NICs setup as a bridge.
The struct for each network device is defined as:
#[derive(PartialEq, Clone, Debug)]
pub(crate) struct UnixNetworkDevice {
name: String,
mac: MacAddr,
interface: NetworkInterface,
statistics: UnixNetworkDeviceStatistics,
}
When the struct is filled in for the eth0 device you get this (wan_device at the beginning is just my tag so I know what I'm looking at):
wan_device Some(UnixNetworkDevice {
name: "eth0",
mac: 00:01:2e:80:3e:1d,
interface: NetworkInterface {
name: "eth0",
index: 2,
mac: Some(00:01:2e:80:3e:1d),
ips: [],
flags: 69699
},
statistics: UnixNetworkDeviceStatistics {
collisions: 0,
multicast: 497,
rx_bytes: 359185,
rx_compressed: 0,
rx_crc_errors: 0,
rx_dropped: 26,
rx_errors: 0,
rx_fifo_errors: 0,
rx_frame_errors: 0,
rx_length_errors: 0,
rx_missed_errors: 0,
rx_nohandler: 0,
rx_over_errors: 0,
rx_packets: 1587,
tx_aborted_errors: 0,
tx_bytes: 74695,
tx_carrier_errors: 0,
tx_compressed: 0,
tx_dropped: 0,
tx_errors: 0,
tx_fifo_errors: 0,
tx_heartbeat_errors: 0,
tx_packets: 474,
tx_window_errors: 0
}
})
I'm also pulling the same information from the Bridge device:
bri_device Some(UnixNetworkDevice {
name: "bri0",
mac: 00:01:2e:80:3e:1d,
interface: NetworkInterface {
name: "bri0",
index: 5,
mac: Some(00:01:2e:80:3e:1d),
ips: [V4(Ipv4Network { addr: 192.168.113.2, prefix: 24 }),
V6(Ipv6Network { addr: fe80::c8ee:a0ff:fe3a:3096, prefix: 64 })],
flags: 69699
},
statistics: UnixNetworkDeviceStatistics {
collisions: 0,
multicast: 0,
rx_bytes: 275467,
rx_compressed: 0,
rx_crc_errors: 0,
rx_dropped: 0,
rx_errors: 0,
rx_fifo_errors: 0,
rx_frame_errors: 0,
rx_length_errors: 0,
rx_missed_errors: 0,
rx_nohandler: 0,
rx_over_errors: 0,
rx_packets: 1371,
tx_aborted_errors: 0,
tx_bytes: 68355,
tx_carrier_errors: 0,
tx_compressed: 0,
tx_dropped: 0,
tx_errors: 0,
tx_fifo_errors: 0,
tx_heartbeat_errors: 0,
tx_packets: 345,
tx_window_errors: 0
}
})
The wan_device doesn't show any IP addresses, since that is assigned to the bridge.
Right now, when it tries to do a clone() of the wan_device, it fails because of the empty ips section in the struct. I would like to copy the IPS portion of the struct from bri_device to wan_device. I hope that is possible.
Here is an MRE that can be made into a project, including the Cargo.toml file after it.
This is the link to the ZIP file of the same:
https://www.dropbox.com/s/7pfxbmv49ra1jxs/Test-OpnFi.zip?dl=0
#[macro_use]
extern crate log;
extern crate lazy_static;
extern crate clap;
extern crate regex;
extern crate simple_logger;
/// Network interface for inform
#[derive(Serialize, Deserialize, PartialEq, Clone, Debug, Default)]
pub struct OpnFiInformNetworkInterface {
pub drops: usize,
pub enabled: bool,
pub full_duplex: bool,
pub gateways: Vec<String>,
pub ip: String,
pub latency: usize,
pub mac: String,
pub name: String,
pub nameservers: Vec<String>,
pub netmask: String,
pub num_port: usize,
pub rx_bytes: usize,
pub rx_dropped: usize,
pub rx_errors: usize,
pub rx_multicast: usize,
pub rx_packets: usize,
pub speed: usize,
pub speedtest_lastrun: usize,
pub speedtest_ping: usize,
pub speedtest_status: String,
pub tx_bytes: usize,
pub tx_dropped: usize,
pub tx_errors: usize,
pub tx_packets: usize,
pub up: bool,
pub uptime: usize,
pub xput_down: usize,
pub xput_up: usize,
}
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
pub(crate) struct Config {
pub inform_url: String,
pub capability: Vec<String>,
pub cfgversion: String,
pub selfrun_guest_mode: String,
pub led_enabled: bool,
pub stun_url: String,
pub mgmt_url: String,
pub authkey: String,
pub use_aes_gcm: bool,
pub report_crash: bool,
}
use pnet::{
datalink::{interfaces, NetworkInterface},
util::MacAddr,
};
use std::str::FromStr;
use std::{fs, io, path};
#[derive(PartialEq, Clone, Debug)]
pub(crate) struct UnixNetworkDevice {
name: String,
mac: MacAddr,
interface: NetworkInterface,
statistics: UnixNetworkDeviceStatistics,
}
impl UnixNetworkDevice {
pub fn new(name: &String) -> io::Result<UnixNetworkDevice> {
let device_path = path::Path::new("/sys/class/net").join(name);
if !device_path.as_path().is_dir() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("Unable to locate UnixNetworkDevice {}", name),
));
}
let mac_string = fs::read_to_string(device_path.join("address"))?;
if mac_string.trim().len() < 15 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Mac address is empty.",
));
}
let mac = MacAddr::from_str(mac_string.trim())
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let interface = interfaces().into_iter().filter(|i| i.name == *name).next();
if interface.is_none() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("Unable to locate NetworkInterface {}", name),
));
}
let interface = interface.unwrap();
let statistics = UnixNetworkDeviceStatistics::new(name);
Ok(UnixNetworkDevice {
name: name.clone(),
mac,
interface,
statistics,
})
}
pub fn name(&self) -> String {
self.name.clone()
}
pub fn mac(&self) -> MacAddr {
self.mac
}
pub fn interface(&self) -> NetworkInterface {
self.interface.clone()
}
pub fn statistics(&self) -> UnixNetworkDeviceStatistics {
self.statistics.clone()
}
}
// ===== Statistics =====
#[derive(PartialOrd, PartialEq, Clone, Debug)]
pub(crate) struct UnixNetworkDeviceStatistics {
pub collisions: usize,
pub multicast: usize,
pub rx_bytes: usize,
pub rx_compressed: usize,
pub rx_crc_errors: usize,
pub rx_dropped: usize,
pub rx_errors: usize,
pub rx_fifo_errors: usize,
pub rx_frame_errors: usize,
pub rx_length_errors: usize,
pub rx_missed_errors: usize,
pub rx_nohandler: usize,
pub rx_over_errors: usize,
pub rx_packets: usize,
pub tx_aborted_errors: usize,
pub tx_bytes: usize,
pub tx_carrier_errors: usize,
pub tx_compressed: usize,
pub tx_dropped: usize,
pub tx_errors: usize,
pub tx_fifo_errors: usize,
pub tx_heartbeat_errors: usize,
pub tx_packets: usize,
pub tx_window_errors: usize,
}
impl UnixNetworkDeviceStatistics {
pub fn new(device_name: &String) -> UnixNetworkDeviceStatistics {
let read_value = |statistic_name: &str| -> io::Result<usize> {
let stat_path = path::Path::new("/sys/class/net")
.join(device_name)
.join("statistics")
.join(statistic_name);
let value = fs::read_to_string(stat_path.as_path())?;
usize::from_str(value.trim())
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
};
UnixNetworkDeviceStatistics {
collisions: read_value("collisions").unwrap_or_default(),
multicast: read_value("multicast").unwrap_or_default(),
rx_bytes: read_value("rx_bytes").unwrap_or_default(),
rx_compressed: read_value("rx_compressed").unwrap_or_default(),
rx_crc_errors: read_value("rx_crc_errors").unwrap_or_default(),
rx_dropped: read_value("rx_dropped").unwrap_or_default(),
rx_errors: read_value("rx_errors").unwrap_or_default(),
rx_fifo_errors: read_value("rx_fifo_errors").unwrap_or_default(),
rx_frame_errors: read_value("rx_frame_errors").unwrap_or_default(),
rx_length_errors: read_value("rx_length_errors").unwrap_or_default(),
rx_missed_errors: read_value("rx_missed_errors").unwrap_or_default(),
rx_nohandler: read_value("rx_nohandler").unwrap_or_default(),
rx_over_errors: read_value("rx_over_errors").unwrap_or_default(),
rx_packets: read_value("rx_packets").unwrap_or_default(),
tx_aborted_errors: read_value("tx_aborted_errors").unwrap_or_default(),
tx_bytes: read_value("tx_bytes").unwrap_or_default(),
tx_carrier_errors: read_value("tx_carrier_errors").unwrap_or_default(),
tx_compressed: read_value("tx_compressed").unwrap_or_default(),
tx_dropped: read_value("tx_dropped").unwrap_or_default(),
tx_errors: read_value("tx_errors").unwrap_or_default(),
tx_fifo_errors: read_value("tx_fifo_errors").unwrap_or_default(),
tx_heartbeat_errors: read_value("tx_heartbeat_errors").unwrap_or_default(),
tx_packets: read_value("tx_packets").unwrap_or_default(),
tx_window_errors: read_value("tx_window_errors").unwrap_or_default(),
}
}
}
impl From<UnixNetworkDevice> for OpnFiInformNetworkInterface {
fn from(value: UnixNetworkDevice) -> Self {
let interface = value.interface();
let stats = value.statistics();
let ip = interface
.ips
.iter()
.filter(|ip| ip.is_ipv4())
.next()
.unwrap();
Self {
drops: stats.rx_dropped + stats.tx_dropped,
enabled: true,
full_duplex: true,
gateways: vec![],
ip: ip.ip().to_string(),
latency: 1,
mac: value.mac().to_string(),
name: value.name().to_string(),
nameservers: vec![],
netmask: ip.mask().to_string(),
num_port: interface.index as usize,
rx_bytes: stats.rx_bytes,
rx_dropped: stats.rx_dropped,
rx_errors: stats.rx_errors,
rx_multicast: 0,
rx_packets: stats.rx_packets,
speed: 1000,
speedtest_lastrun: 0,
speedtest_ping: 0,
speedtest_status: "Idle".to_string(),
tx_bytes: stats.tx_bytes,
tx_dropped: stats.tx_dropped,
tx_errors: stats.tx_errors,
tx_packets: stats.tx_packets,
up: true,
uptime: 0,
xput_down: 0,
xput_up: 0,
}
}
}
fn main() {
let matches = clap::App::new("OpnFi Device")
.version("0.1.0")
.author("James Parks <jrjparks#zathera.com>")
.about("Emulates a UniFi device")
.arg(
clap::Arg::with_name("config")
.short("c")
.long("config")
.value_name("FILE")
.help("Sets a config file path to use")
.takes_value(true),
)
.arg(
clap::Arg::with_name("controller")
.long("controller")
.value_name("FILE")
.help("FQDN or IP Address of UniFi Controller")
.takes_value(true),
)
.arg(
clap::Arg::with_name("wan")
.short("w")
.long("wan")
.value_name("NIC")
.help("Set the nic to report for WAN")
.takes_value(true)
.default_value("eth0"),
)
.arg(
clap::Arg::with_name("lan")
.short("l")
.long("lan")
.value_name("NIC")
.help("Set the nic to report for LAN")
.takes_value(true)
.default_value("eth1"),
)
.arg(
clap::Arg::with_name("bri")
.short("b")
.long("bri")
.value_name("NIC")
.help("Set the nic to report for BRIDGE")
.takes_value(true)
.default_value("bri0"),
)
.get_matches();
let _wan_device = match matches.value_of("wan") {
Some(wan_name) => {
info!("Using {} as WAN device.", wan_name);
UnixNetworkDevice::new(&wan_name.to_string()).ok()
}
None => None,
};
let _lan_device = match matches.value_of("lan") {
Some(lan_name) => {
info!("Using {} as LAN device.", lan_name);
UnixNetworkDevice::new(&lan_name.to_string()).ok()
}
None => None,
};
let _bri_device = match matches.value_of("bri") {
Some(bri_name) => {
info!("Using {} as BRIDGE device.", bri_name);
UnixNetworkDevice::new(&bri_name.to_string()).ok()
}
None => None,
};
println!("wan_device {:?}", _wan_device);
println!("lan_device {:?}", _lan_device);
println!("bri_device {:?}", _bri_device);
// Interfaces
println!("Wan_Interface");
let _wan_interface: Option<OpnFiInformNetworkInterface> = match &mut _wan_device.as_ref()
{
Some(wan) => Some(wan.clone().into()),
_ => None,
};
println!("Lan_Interface");
let _lan_interface: Option<OpnFiInformNetworkInterface> = match &mut _lan_device.as_ref()
{
Some(lan) => Some(lan.clone().into()),
_ => None,
};
println!("Bri_Interface");
let _bri_interface: Option<OpnFiInformNetworkInterface> = match &mut _bri_device.as_ref()
{
Some(bri) => Some(bri.clone().into()),
_ => None,
};
}
[package]
name = "test_opnfi"
version = "0.0.1"
authors = ["Mike Schaffner <mcschaffner#gmail.com>"]
edition = "2018"
license = "Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
lazy_static = "1.4.0"
toml = "0.5.5"
regex = "1.3.1"
rand = "0.7.2"
net2 = "0.2.33"
byteorder = "1.3.2"
serde = "1.0.103"
serde_json = "1.0.42"
sysinfo = "0.9.6"
reqwest = "0.9"
hex = "0.4.0"
pnet = "0.23.0"
clap = "2.33"
ctrlc = "3.1.3"
log = "0.4.8"
simple_logger = "1.3.0"
Your question hits many rust specific questions. Types, size of types, livetime, optional values to just name a few.
Please read Shepmaster's comment and update your question. To give you a direction that may help: https://gist.github.com/rust-play/2289bbcf50caabe7bc0fb397e073e581
// #[derive(Clone)] dosn't work because the unknown size of `value`
struct A {
value: [isize],
}
#[derive(Clone)]
struct B<'a> {
value: Option<&'a [isize]>,
}
fn main() {
//let a: A = A { value: [1] };
//let a1 = a.clone();
let b: B = B { value: None };
let b1 = b.clone();
}
Related
Solana program. failed: Failed to serialize or deserialize account data: Unknown'
I am getting an error: Failed to serialize or deserialize account data: Unknown'. I'm trying to get data like this: let mut bet_account = BidData::try_from_slice(&bet.data.borrow()[..])?;, where BidData contains the field bids: Vec<Bid>. #[derive(BorshSerialize, BorshDeserialize, Debug)] pub struct Bid { /// XJUST coins pub xjust: u64, /// selected side pub side: u8, /// user key pub pubkey: String, } #[derive(BorshDeserialize, BorshSerialize, Debug)] pub struct BidData { // list bids pub bids: Vec<Bid> } The problem is described in more detail here.
Easier to just use what the derive macro for borsh provided: #[derive(BorshSerialize, BorshDeserialize, Debug)] pub struct Bid { /// XJUST coins pub xjust: u64, /// selected side pub side: u8, /// user key pub pubkey: String, } #[derive(BorshDeserialize, BorshSerialize, Debug, Default)] pub struct BidData { // list bids pub bids: Vec<Bid>, } #[cfg(test)] mod test { use borsh::BorshSerialize; use super::{Bid, BidData}; #[test] fn test_ser() { let bid1 = Bid { xjust: 100_000, side: 2, pubkey: "".to_string(), }; let mut bid_data = BidData::default(); bid_data.bids.push(bid1); let ser_bid_data = bid_data.try_to_vec().unwrap(); println!("{:?}", ser_bid_data); let deser_bid_data = BidData::try_from_slice(&ser_bid_data); println!("{:?}", deser_bid_data); } } Produces: running 1 test [1, 0, 0, 0, 160, 134, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0] Ok(BidData { bids: [Bid { xjust: 100000, side: 2, pubkey: "" }] })
how to define multi parameter with from function in rust
Now I want to map object from Favorites to FavMusicResponse, the Favorites object was selected from database and the FavMusicResponse entity was return to the client. I define the map function like this way in FavMusicResponse: impl From<&Favorites> for FavMusicResponse { fn from(f: &Favorites, music: Music) -> Self { Self{ id: f.id, song_id: None, created_time: f.created_time, updated_time: f.updated_time, user_id: 0, source_id: "".to_string(), like_status: 0, source: 0, playlist_id: 0, play_count: 0, fetched_download_url: None, downloaded: None, music: Default::default() } } } most of the fields from Favorites fields are the same with FavMusicResponse, the only difference is that music was passed from another entity. This is my FavMusicResponse define: #[derive( Serialize, Queryable, Deserialize,Default, Clone)] pub struct FavMusicResponse{ pub id: i64, pub song_id: Option<i64>, pub created_time: i64, pub updated_time: i64, pub user_id: i64, pub source_id: String, pub like_status: i32, pub source: i32, pub playlist_id: i64, pub play_count: i32, pub fetched_download_url: Option<i32>, pub downloaded: Option<i32>, pub music: Music } the compiler tell me that from expected 1 parameter, found 2, what should I do do pass 2 or more parameter into the composite function in rust? I invoke the function like this way: let filtered_music:Vec<_> = musics.iter() .filter(|item| item.source_id == fav.source_id) .map(|item|FavMusicResponse::from(fav,item.clone())) .collect(); I want to passed two entity and composite to the finally FavMusicResponse entity. what should I do to make it work like that? This is my minimal reproduce that could run in rust playground to figure out where is going wrong: fn main() { let music = Music{ id: 1 }; let favMusic = Favorites{ id: 1 }; let musicRes = FavMusicResponse::from(favMusic,music); } pub struct Music { pub id: i64 } pub struct Favorites { pub id: i64 } pub struct FavMusicResponse { pub id: i64, pub music:Music } impl From<Favorites> for FavMusicResponse { fn from(f: Favorites, music: Music) -> Self { Self{ id: f.id, music: music } } }
From trait can't take two parameters only one, it's define that way, the only solution if you really want to use From trait is to transform your two parameter into one, a quick solution is to use a tuple: impl From<(Favorites, Music)> for FavMusicResponse { fn from((f, music): (Favorites, Music)) -> Self { Self { id: f.id, music, } } } // let musicRes = FavMusicResponse::from((favMusic, music)); That said you could also just have a new() method on your type: impl FavMusicResponse { fn new(f: Favorites, music: Music) -> Self { Self { id: f.id, music, } } } // let musicRes = FavMusicResponse::new(favMusic, music);
is it possible to get pagination info from rust pagination query result
I am using rust diesel to do a pagination query right now. I get the pagination information from request right now, I was wonder is it possible to get pagination information from Query result? This is my code: pub fn fav_music_query<T>(request: Json<FavMusicRequest>) -> Paginated<Vec<Favorites>> { use crate::model::diesel::rhythm::rhythm_schema::favorites::dsl::*; let connection = config::establish_music_connection(); let query = favorites.filter(like_status.eq(1)).paginate(request.pageNum).per_page(request.pageSize); let query_result = query.load_and_count_pages::<Favorites>(&connection).unwrap(); let page_result = Paginated{ query: query_result.0, page: request.pageNum, per_page: request.pageSize, is_sub_query: false }; return page_result; } from the request I could only get pageSize and pageNum, but I did not know the total size. what is the best way the get the pagination information? this is my pagination code: use diesel::prelude::*; use diesel::query_dsl::methods::LoadQuery; use diesel::query_builder::{QueryFragment, Query, AstPass}; use diesel::pg::Pg; use diesel::sql_types::BigInt; use diesel::QueryId; use serde::{Serialize, Deserialize}; pub trait PaginateForQueryFragment: Sized { fn paginate(self, page: i64) -> Paginated<Self>; } impl<T> PaginateForQueryFragment for T where T: QueryFragment<Pg>{ fn paginate(self, page: i64) -> Paginated<Self> { Paginated { query: self, per_page: 10, page, is_sub_query: true, } } } #[derive(Debug, Clone, Copy, QueryId, Serialize, Deserialize, Default)] pub struct Paginated<T> { pub query: T, pub page: i64, pub per_page: i64, pub is_sub_query: bool } impl<T> Paginated<T> { pub fn per_page(self, per_page: i64) -> Self { Paginated { per_page, ..self } } pub fn load_and_count_pages<U>(self, conn: &PgConnection) -> QueryResult<(Vec<U>, i64)> where Self: LoadQuery<PgConnection, (U, i64)>, { let per_page = self.per_page; let results = self.load::<(U, i64)>(conn)?; let total = results.get(0).map(|x| x.1).unwrap_or(0); let records = results.into_iter().map(|x| x.0).collect(); let total_pages = (total as f64 / per_page as f64).ceil() as i64; Ok((records, total_pages)) } } impl<T: Query> Query for Paginated<T> { type SqlType = (T::SqlType, BigInt); } impl<T> RunQueryDsl<PgConnection> for Paginated<T> {} impl<T> QueryFragment<Pg> for Paginated<T> where T: QueryFragment<Pg>, { fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> { out.push_sql("SELECT *, COUNT(*) OVER () FROM "); if self.is_sub_query { out.push_sql("("); } self.query.walk_ast(out.reborrow())?; if self.is_sub_query { out.push_sql(")"); } out.push_sql(" t LIMIT "); out.push_bind_param::<BigInt, _>(&self.per_page)?; out.push_sql(" OFFSET "); let offset = (self.page - 1) * self.per_page; out.push_bind_param::<BigInt, _>(&offset)?; Ok(()) } } #[derive(Debug, Clone, Copy, QueryId)] pub struct QuerySourceToQueryFragment<T> { query_source: T, } impl<FC, T> QueryFragment<Pg> for QuerySourceToQueryFragment<T> where FC: QueryFragment<Pg>, T: QuerySource<FromClause=FC>, { fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> { self.query_source.from_clause().walk_ast(out.reborrow())?; Ok(()) } } pub trait PaginateForQuerySource: Sized { fn paginate(self, page: i64) -> Paginated<QuerySourceToQueryFragment<Self>>; } impl<T> PaginateForQuerySource for T where T: QuerySource { fn paginate(self, page: i64) -> Paginated<QuerySourceToQueryFragment<Self>> { Paginated { query: QuerySourceToQueryFragment {query_source: self}, per_page: 10, page, is_sub_query: false, } } } and this is my FavMusicRequest that define the pagination query information: #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] #[allow(non_snake_case)] pub struct FavMusicRequest { pub userId: i64, pub pageNum: i64, pub pageSize: i64 } and this is the query entity from database: #[derive( Serialize, Queryable, Deserialize,Default)] pub struct Favorites { pub id: i64, pub song_id: Option<i64>, pub created_time: i64, pub updated_time: i64, pub user_id: i64, pub source_id: String, pub like_status: i32, pub source: i32, pub playlist_id: i64, pub play_count: i32, pub fetched_download_url: Option<i32>, pub downloaded: Option<i32> } and this is the request defined with rocket: #[post("/v1/page",data = "<request>")] pub fn page(request: Json<FavMusicRequest>) -> content::Json<String> { let fav_musics = fav_music_query::<Vec<Favorites>>(request); let res = ApiResponse { result: fav_musics, ..Default::default() }; let response_json = serde_json::to_string(&res).unwrap(); return content::Json(response_json); }
You can return the results in QueryResult<(....)> in the load_and_count_pages. Here is a working example: use diesel::pg::Pg; use diesel::prelude::*; use diesel::query_builder::*; use diesel::query_dsl::methods::LoadQuery; use diesel::sql_types::BigInt; pub trait Paginate: Sized { fn paginate(self, page: i64) -> Paginated<Self>; } impl<T> Paginate for T { fn paginate(self, page: i64) -> Paginated<Self> { Paginated { query: self, per_page: DEFAULT_PER_PAGE, page, } } } const DEFAULT_PER_PAGE: i64 = 100; #[derive(Debug, Clone, Copy, QueryId)] pub struct Paginated<T> { query: T, page: i64, per_page: i64, } impl<T> Paginated<T> { pub fn per_page(self, per_page: i64) -> Self { Paginated { per_page, ..self } } pub fn load_and_count_pages<U>(self, conn: &PgConnection) -> QueryResult<(Vec<U>, i64)> where Self: LoadQuery<PgConnection, (U, i64)>, { let _per_page = self.per_page; let results = self.load::<(U, i64)>(conn)?; let total = results.get(0).map(|x| x.1).unwrap_or(0); let records = results.into_iter().map(|x| x.0).collect(); Ok((records, total)) } } impl<T: Query> Query for Paginated<T> { type SqlType = (T::SqlType, BigInt); } impl<T> RunQueryDsl<PgConnection> for Paginated<T> {} impl<T> QueryFragment<Pg> for Paginated<T> where T: QueryFragment<Pg>, { fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> { out.push_sql("SELECT *, COUNT(*) OVER () FROM ("); self.query.walk_ast(out.reborrow())?; out.push_sql(") t LIMIT "); out.push_bind_param::<BigInt, _>(&self.per_page)?; out.push_sql(" OFFSET "); let offset = (self.page - 1) * self.per_page; out.push_bind_param::<BigInt, _>(&offset)?; Ok(()) } } Then you can define a pagination handler. #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Cursor { pub total_pages: i32, pub filters: Vec<String>, } #[derive(Serialize)] pub struct PaginationResult<T> where T: Serialize, { pub records: Vec<T>, pub cursor: Cursor, } Then you can now do: pub fn fav_music_query<T>(request: Json<FavMusicRequest>) -> PaginationResult<Vec<Favorites>> { use crate::model::diesel::rhythm::rhythm_schema::favorites::dsl::*; let connection = config::establish_music_connection(); let query = favorites .filter(like_status.eq(1)) .paginate(request.pageNum) .per_page(request.pageSize); let (favorites, pages) = query .load_and_count_pages::<Favorites>(&connection) .unwrap(); return PaginationResult { records: favorites, cursor: Cursor { total_pages: pages as i32, filters: vec![], }, }; } My example just gets the total number of pages. You can add more all you need.
how to handle the moved exception in a loop in rust
I want to map entity from one Vec(this entity list search from database) into another Vec(this response entity list return to frontend) in rust, this is my code: fn main() { let musics:Vec<Music> = Vec::new(); for x in 0..10 { let filtered_music:Vec<Music> = musics.into_iter() .filter(|item| item.source_id == "1") .collect(); let resp = MusicRes{ music: take(filtered_music, 0).unwrap() }; } } fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> { if index < vec.len() { Some(vec.swap_remove(index)) } else { None } } pub struct Music { pub id: i64, pub name: String, pub artists: String, pub album_id: i64, pub publishtime: i64, pub status: i32, pub duration: i32, pub source_id: String, pub source: i32, pub created_time: i64, pub updated_time:i64, pub album: String, pub fetched_download_url: i32 } pub struct MusicRes { pub music:Music } this code give me tips that musics was moved. I could change the musics to &musics, but the returned response need to Music. How to handle this situation properly?
I'm not exactly sure what your requirements are, ie. what's the point of the 0..10 then taking the 0th element, but you could do something like this: let musics: Vec<_> = musics .into_iter() .take(10) .filter(|m| m.source_id == "1") .map(|m| MusicRes { music: m }) .collect();
How do I serialize and deserialize a remote crate's enum as a number?
I have been trying to setup the following configuration for the serialport crate in Rust with serde, so I can intuitively supply 7 in my config for data_bits, but it will be deserialized as serialport::DataBits::Seven. Unfortunately, it seemingly fails the moment I want it to be a number (7) and not a string (seven). Test case cargo.toml [package] name = "serde_error" version = "0.1.0" authors = ["Jason Miller"] edition = "2018" [dependencies] serialport = "3.3.0" serde = { version = "1.0", features = ["derive"] } ron = "0.5.1" The following results in the error: 6:16: Expected identifier main.rs use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] #[serde(remote = "serialport::DataBits")] pub enum DataBitsDef { #[serde(rename = "5")] Five, #[serde(rename = "6")] Six, #[serde(rename = "7")] Seven, #[serde(rename = "8")] Eight, } fn default_data_bits() -> serialport::DataBits { serialport::DataBits::Eight } #[derive(Debug, Serialize, Deserialize)] pub struct TransceiverSettings { pub vid: u16, pub pid: u16, pub baud_rate: u32, #[serde(default = "default_data_bits", with = "DataBitsDef")] pub data_bits: serialport::DataBits, } impl Default for TransceiverSettings { fn default() -> Self { Self { vid: 0x2341, pid: 0x0043, baud_rate: 115_200, data_bits: serialport::DataBits::Eight, } } } const TRX_CONFIG: &str = " ( vid: 0x2341, pid: 0x0043, baud_rate: 9600, data_bits: 7, ) "; fn main() { match ron::de::from_str::<TransceiverSettings>(&TRX_CONFIG) { Err(e) => eprintln!("{}", e), Ok(c) => println!("{:?}", c), } } Oddly enough, writing 7 as seven succeeds and returns: TransceiverSettings { vid: 9025, pid: 67, baud_rate: 9600, data_bits: Seven } main.rs use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] #[serde(remote = "serialport::DataBits")] pub enum DataBitsDef { #[serde(rename = "5")] Five, #[serde(rename = "6")] Six, #[serde(rename = "seven")] Seven, #[serde(rename = "8")] Eight, } fn default_data_bits() -> serialport::DataBits { serialport::DataBits::Eight } #[derive(Debug, Serialize, Deserialize)] pub struct TransceiverSettings { pub vid: u16, pub pid: u16, pub baud_rate: u32, #[serde(default = "default_data_bits", with = "DataBitsDef")] pub data_bits: serialport::DataBits, } impl Default for TransceiverSettings { fn default() -> Self { Self { vid: 0x2341, pid: 0x0043, baud_rate: 115_200, data_bits: serialport::DataBits::Eight, } } } const TRX_CONFIG: &str = " ( vid: 0x2341, pid: 0x0043, baud_rate: 9600, data_bits: seven, ) "; fn main() { match ron::de::from_str::<TransceiverSettings>(&TRX_CONFIG) { Err(e) => eprintln!("{}", e), Ok(c) => println!("{:?}", c), } } serde_repr One of the given examples in the serde documentation seems relevant to my case, but I haven't managed to get it working with my setup. Serialize enum as number The serde_repr crate provides alternative derive macros that derive the same Serialize and Deserialize traits but delegate to the underlying representation of a C-like enum. This allows C-like enums to be formatted as integers rather than strings in JSON #[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)] #[repr(u8)] enum SmallPrime { Two = 2, Three = 3, Five = 5, Seven = 7, }
Support for #[serde(remote)] is not present in serde_repr 0.1.5. You will need to submit a pull request or issue to add support for it. Instead, follow the advice in How to transform fields during deserialization using Serde? and How to transform fields during serialization using Serde?: use serde::{Deserialize, Serialize}; mod shim { use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use serialport::DataBits; pub fn serialize<S>(v: &DataBits, s: S) -> Result<S::Ok, S::Error> where S: Serializer, { use DataBits::*; let v: u8 = match v { Five => 5, Six => 6, Seven => 7, Eight => 8, }; v.serialize(s) } pub fn deserialize<'de, D>(d: D) -> Result<DataBits, D::Error> where D: Deserializer<'de>, { use DataBits::*; match u8::deserialize(d)? { 5 => Ok(Five), 6 => Ok(Six), 7 => Ok(Seven), 8 => Ok(Eight), o => Err(D::Error::custom(format_args!("Invalid value {}", o))), } } } #[derive(Debug, Serialize, Deserialize)] pub struct TransceiverSettings { pub vid: u16, pub pid: u16, pub baud_rate: u32, #[serde(default = "default_data_bits", with = "shim")] pub data_bits: serialport::DataBits, }