How to validate option parameter value from the struct - rust

I am working on rust-lang facing issue when i am trying do validation on option parameter during the updating. Below is demo version of code. Please do help me. Better to use match pattern or if condition statement.
#[derive(Deserialize)]
struct UserUpdateReq {
uuid: Option<i32>,
first_name: Option<String>,
last_name: Option<String>,
}
fn update_user(req: Json) => Result<Response<Vec<i32>>, String>{
let req: UserUpdateReq = try_s!(json::from_value(req));
// Here I need to validate optional parameters
// checking both parameters have a value. In case both are None, return err message
// if any one value is present update that value.
}

If you want to check that at least one of first_name and last_name are provided, you can do it on a case-by-case basis with:
match (req.first_name, req.last_name) {
(Some(first_name), Some(last_name)) => {
// update both
}
(None, Some(last_name)) => {
// update last name
}
(Some(first_name), None) => {
// update first name
}
(None, None) => {
// error
}
Or
if req.first_name.is_none() && req.last_name.is_none () {
// error
} else {
if let Some(first_name) = req.first_name {
// update first name
}
if let Some(last_name) = req.last_name {
// update last name
}
}

Related

Creating code based on value of macro agrument rust

macro_rules! retry_put {
($mod_name:ident, $data_type:ty) => {{
fn $mod_name() {
// somelike
if $mod_name == "red" {
// generate code written here and not the one in else block
return u8;
}
else {
// generate code written here and not the one in if
return "string";
}
}
}
}
I am tring to change the return type based on input basically, if input is true return string else return int.
Or maybe give example for :
give example where we are accepting a arguement in macro and if its even calulate factorial of 5 and return it as integer and if the agruement is odd calculate the factoreial of 5 and return it as string. And name of both functions should be same. and logic of calculating 5! should not be repeated.
You can overload a macro like this:
macro_rules! retry_put {
(red, $data_type:ty) => {{
fn red() {
return u8;
}
}
}
($mod_name:ident, $data_type:ty) => {{
fn $mod_name() {
return "string";
}
}
}
}
See macro_rules!.

Swift UI, removing item from array, while looping in it throws Fatal Error: Index out of range [duplicate]

I am trying to remove rows inside a ForEach. Removing the last row always throws an index out of range exception. Removing any other row does not.
ForEach(Array(player.scores.enumerated()), id: \.element) { index, score in
HStack {
if self.isEditSelected {
Button(action: {
self.player.scores.remove(at: index)
}, label: {
Image("delete")
})
}
TextField("\(score)", value: self.$player.scores[index], formatter: NumberFormatter())
}
}
I have tried using ForEach(player.indices...) & ForEach(player.scores...), but see the same problem.
Looks to me like the crash happens here self.$player.scores[index], as hardcoding the index to any value other that the last row is working.
Does anyone know how to fix this? Or if there is a better approach.
Here is fix
ForEach(Array(player.scores.enumerated()), id: \.element) { index, score in
HStack {
if self.isEditSelected {
Button(action: {
self.player.scores.remove(at: index)
}, label: {
Image("delete")
})
}
TextField("\(score)", value: Binding( // << use proxy binding !!
get: { self.player.scores[index] },
set: { self.player.scores[index] = $0 }),
formatter: NumberFormatter())
}
}
Based on #Asperi answer
public extension Binding where Value: Equatable {
static func proxy(_ source: Binding<Value>) -> Binding<Value> {
self.init(
get: { source.wrappedValue },
set: { source.wrappedValue = $0 }
)
}
}
You can use this as follows:
TextField("Name", text: .proxy($variable))
Xcode 13.0 beta introduced a new way to establish two-way-bindings between the elements of a collection and the views built by ForEach / List.
This method fixes the crash related to deleting the last row.
struct Score: Identifiable {
let id = UUID()
var value: Int
}
struct Player {
var scores: [Score] = (1...10).map {_ in .init(value: Int.random(in: 0...25))}
}
struct BindingTest: View {
#State private var player = Player()
var body: some View {
List {
ForEach($player.scores) { $score in
HStack {
TextField("\(score.value)", value: $score.value,
formatter: NumberFormatter())
}
}
.onDelete { player.scores.remove(atOffsets: $0)}
}
}
}

How to limit function input to dynamically assigned keys of an object in typescript?

lately I am trying to create a placeholder object that I will be able to use with typescript.
Idea is to have an empty object and two functions:
one to add new key to a placeholder object with another object as a value ( 'add' function )
and one to get this value by passing a key that already exists in a placeholder ( 'get' function )
I would like typescript to forbid to type keys that already exist in placeholder in 'add' function.
Also I would like to get suggestions while typing key in 'get' function.
Last thing that I would like to achieve is to have type of an object that is returned from 'get' function instead of 'any' or 'object'
Here is the sample code with some basic typing:
let placeholder = {}
function add(key: string, test: object) {
placeholder[ key ] = test
}
function get(key: string ) {
return placeholder[key]
}
add('test1', { val: 1 }) // here 'test1' is ok
add('test1', { val: 2 }) // here 'test1' should rise an error
let t1 = get('') // here 'test1' and should be suggested
t1.val // here t1 should have type { val: number }
So far I have tried using generic types with things like:
function add( key: Omit< string, keyof typeof placeholder >, test: object ) { ... } // it is casting key to properties of string
function get< Key extends keyof typeof placeholder > ( key: Key ) { ... } // it only works with static keys
That is not possible. This would require the type of the object to change, but types are static.
The only thing you could do would be to return an object from your add function with a modified type and then continue calls on that object.
Example of that approach (still has one typing issue i set to ignore):
class Placeholder<T>
{
constructor(private entries: T)
{
}
add<K extends string, V>(key: Exclude<K, keyof T>, value: V): Placeholder<T & { [X in K]: V }> {
const newEntries = { ...this.entries, [key]: value };
// #ts-ignore
return new Placeholder(newEntries);
}
get(key: keyof T) {
return this.entries[key];
}
}
const ph = new Placeholder({})
.add('test1', { val: 1 }) // here 'test1' is ok
.add('test1', { val: 2 }) // here 'test1' should rise an error
let t1 = ph.get('test1') // here 'test1' and should be suggested
t1.val // here t1 should have type { val: number }
[Playground Link]

Gtk Widgets returning None even when they hold data

I have a filechoosernative and a comboboxtext in my UI. Now I am trying to extract data from those two inside callbacks but they are returning me None even though they clearly have data set by the user. Why is this happening?
Excerpt from https://gitlab.com/9898287/nixwriter/-/blob/rir/src/frontend/mod.rs#L41
fn get_selected_file(&self) -> Option<std::path::PathBuf> {
let selected_file = self.fcn.get_filename();
dbg!(&selected_file);
selected_file
}
Excerpt from https://gitlab.com/9898287/nixwriter/-/blob/rir/src/frontend/mod.rs#L35
fn get_selected_device(&self) -> Option<udisks::DiskDevice> {
// Combo box text only stores a Gstring (Device ID)
// Search through the list of devices from udisks2 again
// and find the device with matching device ID
let selected_device = match self.lsblk_cbt.get_active_text() {
Some(txt) => {
dbg!(&txt);
for disk in crate::aux::backend::get_disks() {
if disk.drive.id == txt {
return Some(disk);
}
}
dbg!("No matching device found. Must reload.");
None
}
None => {
dbg!("lsblk_cbt is returning nothing");
None
}
};
dbg!(&selected_device);
selected_device
}
Both return None in https://gitlab.com/9898287/nixwriter/-/blob/rir/src/frontend/mod.rs#L110
fn set_lsblk_cbt(&mut self) {
let cbt = self.lsblk_cbt.clone();
for ddev in crate::aux::backend::get_disks() {
cbt.append_text(&ddev.drive.id);
}
let (device_chosen, file_chosen) = (
self.get_selected_device().is_some(),
self.get_selected_file().is_some(),
);
let start = self.start.clone();
cbt.connect_changed(move |_| {
start.set_sensitive(device_chosen && file_chosen);
dbg!("From set_lsblk_cbt", device_chosen, file_chosen);
});
}
even after the user has set a file and selected an item from ComboboxText.

Add/Update parameter for a Context

In Dialogflow fulfillment I am trying to add or update parameters for a context.
let currentContext = agent.context.get('setupcall-followup');
console.log(agent.context.get('setupcall-followup').parameters); //1
currentContext.parameters.date = '2019-09-18T12:00:00-04:00';
currentContext.parameters.time = '2019-09-17T13:00:00-04:00';
currentContext.parameters['Test'] = 'Test';
console.log(agent.context.get('setupcall-followup').parameters); //2
agent.context.set(currentContext); //Seems to not be needed, since it is by reference
console.log(agent.context.get('setupcall-followup').parameters); //3, same as #2
By #2 & #3 the log shows that it was updated.
But in the Diagnostic Info > Raw API Response, the outputContext information is still the original inputContext, before modification.
What I can do:
Add a new context, with it's own parameters.
What I can't do
Get a context & change a parameter
This is the only way I finally got it to work.
Use a custom context & recreate it completely, every-time.
FYI Code below requires lodash for _.merge
function getSessionData() {
if(agent.context.get('session_details')) {
return agent.context.get('session_details').parameters.sessionDetails;
} else {
return;
}
}
function setSessionData(data) {
if(agent.context.get('session_details')) {
let session = agent.context.get('session_details').parameters.sessionDetails; //Extract the data from the existing "session_details" context
_.merge(session, data); //Update our data
let sessionContext = { //Define the complete context object again
name: "session_details",
lifespan: 5,
parameters: {
sessionDetails: session
}
}
agent.context.set(sessionContext);
} else {
let sessionContext = { //Define the complete context object again
name: "session_details",
lifespan: 5,
parameters: {
sessionDetails: data
}
}
agent.context.set(sessionContext);
}
}
I think this may help.
const parameters = {'param1':value, 'param2': value};
agent.context.set(context, 5, parameters); //here "5" is lifespan.
Tell me if it worked.

Resources