Updating a struct with reflect - go

I want to make my code shorter and I'm trying to understand how reflect works. The code below works (the real code has many more structs and are much longer). So shortly the function processInput gets string data from a TCP connection and it is used to populate the Hyperdeck struct.
type configuration struct {
videoInput string `cmd:"video input:"`
audioMapping int64 `cmd:"audio mapping:"`
genlockInputResync bool `cmd:"genlock input resync:"`
}
type Hyperdeck struct {
configuration configuration
}
func (hd *Hyperdeck) processInput(s string) {
switch hd.multilineCmd {
case "configuration":
if s != "\r\n" {
if strings.HasPrefix(s, "video input:") {
hd.configuration.videoInput = strings.TrimSpace(s[strings.Index(s, ":")+1 : len(s)-1])
} else if strings.HasPrefix(s, "audio mapping:") {
hd.configuration.audioMapping = stringToInt(strings.TrimSpace(s[strings.Index(s, ":")+1:len(s)-1]), hd)
} else if strings.HasPrefix(s, "genlock input resync:") {
hd.configuration.genlockInputResync = stringToBool(strings.TrimSpace(s[strings.Index(s, ":")+1:len(s)-1]), hd)
}
} else {
hd.multilineCmd = ""
}
}
switch {
case strings.Contains(strings.ToLower(s), "configuration"):
hd.multilineCmd = "configuration"
}
}
I was thinking of making something like this that loops the stuct and identifies the type but I can't figure out how to update the struct. I've read and tried things from multiple websites but I just can't get it right.
func (hd *Hyperdeck) processInput(s string) {
switch hd.multilineCmd {
case "configuration":
if s != "\r\n" {
v := reflect.ValueOf(hd.configuration)
t := v.Type()
for i := 0; i < v.NumField(); i++ {
if strings.HasPrefix(s, t.Field(i).Tag.Get("cmd")) {
if t.Field(i).Type.String() == "string" {
// UPDATE hd.configuration.videoInput
} else if t.Field(i).Type.String() == "int" {
//UPDATE hd.configuration.audioMapping
} else if t.Field(i).Type.String() == "bool" {
//UPDATE hd.configuration.genlockInputResync
}
}
}
} else {
hd.multilineCmd = ""
}
}
switch {
case strings.Contains(strings.ToLower(s), "configuration"):
hd.multilineCmd = "configuration"
}
}
I think this code is usable for strings but can't figure out how to address it...
...FieldByName(types.Field(i).Name).SetString(strings.TrimSpace(s[strings.Index(s, ":")+1 : len(s)-1]))
And maybe the most important question, should I do it with reflect or leave it as it is now?

Related

Argument passed to call that takes no arguments.. Firebase

Not sure why i'm getting this.. any suggestions would be grateful!
I ran into issues with my original coding where I had Firebase pod and Firebase Package.. so I started from scratch since that wasnt fixing itself.. now I get this.. and I am at a loss for how to resolve it.
static func fetchUsers() -> AnyPublisher<[UserProfile], Error> {
Future< [UserProfile], Error > { promise in
self.db.collection("Users")
.getDocuments { (snapshot, error) in
if let error = error {
promise(.failure(error))
return
}
guard let snapshot = snapshot else {
promise(.failure(FirebaseError.badSnapshot))
return
}
var users = [UserProfile]()
snapshot.documents.forEach { document in
print(users.count)
if let user = try? document.data(as: UserProfile.self){
if users.contains(where: { $0.id == user.id}) {return}
users.append(user)
} else {
print("Not working")
}
}
promise(.success(users))
}
}
.eraseToAnyPublisher()
}
I believe this is the syntax you're after:
var users = [UserProfile]()
users = snapshot.documents.compactMap { (document) -> UserProfile? in
if users.contains(where: { $0.id == user.id}) {
return nil
} else {
return try? document.data(as: UserProfile.self)
}
}
Also be aware that when you iterate something in Swift and encounter a false condition on an iteration, return will return out of the greater scope, not just that iteration. Therefore, use continue.
for x in y {
guard x > 0 else {
continue // continues loop
}
// ...
}

What is the meaning of `copyOnWriteContext` in module `github.com/google/btree`?

Recently, I read the source code of google/btree. But I'am conflused by the struct copyOnWriteContext. It is used in node function mutableFor, like following
func (n *node) mutableFor(cow *copyOnWriteContext) *node {
if n.cow == cow {
return n
}
fmt.Println("new node?")
out := cow.newNode()
if cap(out.items) >= len(n.items) {
out.items = out.items[:len(n.items)]
} else {
out.items = make(items, len(n.items), cap(n.items))
}
copy(out.items, n.items)
// Copy children
if cap(out.children) >= len(n.children) {
out.children = out.children[:len(n.children)]
} else {
out.children = make(children, len(n.children), cap(n.children))
}
copy(out.children, n.children)
return out
}
I review all the code in this module, and found that there is only one place create the copyOnWriteContext's instance. It is when the tree is created.
func New(degree int) *BTree {
return NewWithFreeList(degree, NewFreeList(DefaultFreeListSize))
}
So what is the meaning for mutableFor. Because there is only one copyOnWriteContext in the entire code. The n.cow always equals param cow.
n.cow can be nil.
// freeNode frees a node within a given COW context, if it's owned by that
// context. It returns what happened to the node (see freeType const
// documentation).
func (c *copyOnWriteContext) freeNode(n *node) freeType {
if n.cow == c {
// clear to allow GC
n.items.truncate(0)
n.children.truncate(0)
n.cow = nil
if c.freelist.freeNode(n) {
return ftStored
} else {
return ftFreelistFull
}
} else {
return ftNotOwned
}
}

How do I conditionally check if an enum is one variant or another?

I have an enum with two variants:
enum DatabaseType {
Memory,
RocksDB,
}
What do I need in order to make a conditional if inside a function that checks if an argument is DatabaseType::Memory or DatabaseType::RocksDB?
fn initialize(datastore: DatabaseType) -> Result<V, E> {
if /* Memory */ {
//..........
} else if /* RocksDB */ {
//..........
}
}
First have a look at the free, official Rust book The Rust Programming Language, specifically the chapter on enums.
match
fn initialize(datastore: DatabaseType) {
match datastore {
DatabaseType::Memory => {
// ...
}
DatabaseType::RocksDB => {
// ...
}
}
}
if let
fn initialize(datastore: DatabaseType) {
if let DatabaseType::Memory = datastore {
// ...
} else {
// ...
}
}
==
#[derive(PartialEq)]
enum DatabaseType {
Memory,
RocksDB,
}
fn initialize(datastore: DatabaseType) {
if DatabaseType::Memory == datastore {
// ...
} else {
// ...
}
}
matches!
This is available since Rust 1.42.0
fn initialize(datastore: DatabaseType) {
if matches!(datastore, DatabaseType::Memory) {
// ...
} else {
// ...
}
}
See also:
How to compare enum without pattern matching
Read from an enum without pattern matching
Compare enums only by variant, not value
https://doc.rust-lang.org/std/macro.matches.html
// A simple example that runs in rust 1.58:
enum Aap {
Noot(i32, char),
Mies(String, f64),
}
fn main() {
let aap: Aap = Aap::Noot(42, 'q');
let noot: Aap = Aap::Mies(String::from("noot"), 422.0);
println!("{}", doe(aap));
println!("{}", doe(noot));
}
fn doe(a: Aap) -> i32 {
match a {
Aap::Noot(i, _) => i,
Aap::Mies(_, f) => f as i32,
}
}

How to populate Enum from the values retrieved from Database

Looking at the example here at Message Controller for Pizza Example, if I want to populate Size or Kind based on some user input and make a call to the database, how would I do that?
So far as I know, there is not an easy way to populate the Enum at runtime.
It looks like this hasn't been implemented yet. I took a look inside https://github.com/Microsoft/BotBuilder/blob/master/CSharp/Library/FormFlow/FormBuilder.cs and found this:
internal static void TypePaths(Type type, string path, List<string> paths)
{
if (type.IsClass)
{
if (type == typeof(string))
{
paths.Add(path);
}
else if (type.IsIEnumerable())
{
var elt = type.GetGenericElementType();
if (elt.IsEnum)
{
paths.Add(path);
}
else
{
// TODO: What to do about enumerations of things other than enums?
}
}
else
{
FieldPaths(type, path, paths);
}
}
else if (type.IsEnum)
{
paths.Add(path);
}
else if (type == typeof(bool))
{
paths.Add(path);
}
else if (type.IsIntegral())
{
paths.Add(path);
}
else if (type.IsDouble())
{
paths.Add(path);
}
else if (type.IsNullable() && type.IsValueType)
{
paths.Add(path);
}
else if (type == typeof(DateTime))
{
paths.Add(path);
}
}
Notice the TODO about enumerations other than enums.
Outside of the FormBuilder we can use PromptDialog.Choice which takes an IEnumerable<> of your options.
It is possible to chain dialogs together, so you may have to split your FormDialog into two with the PromptDialog in-between.
Alternatively take a fork of BotBuilder and implement the TODO!

Swift 3: how to write this for(;;) loop

Looks like Apple doesn't like C loops, but doesn't provide good approach over it (or I couldn't find it). I have such loop to go from some view to the root in UI hierarchy:
for var parentView = view; parentView != nil; parentView = parentView.parent {
...
}
How to write this in Swift 3 manner?
This would be a way to do it in Swift 3:
var parentView: View! = view
while parentView != nil {
// Do stuff
parentView = parentView.parent
}
If you want to group the loop progression stuff next to while and not at the end of block, you may use defer, like this:
var parentView: View! = view
while parentView != nil {
defer { parentView = parentView.parent }
// Do stuff
}
If you want to limit the scope of parentView, you can encapsulate everything in a do block:
do {
var parentView: View! = view
while parentView != nil {
defer { parentView = parentView.parent }
// Do stuff
}
}
But it's quite verbose so you could define a new generic function for similar loops, like this:
func kindaCStyleLoop<T>(first: T, obtainNext: T -> T?, action: T -> ()) {
var current: T! = first
repeat {
action(current)
current = obtainNext(current)
} while current != nil
}
kindaCStyleLoop(view, obtainNext: { $0.parent }) {
// Do stuff with $0
}
And a last one that relies on GeneratorType and SequenceType to enable using the for-in-loop syntax:
struct CStyleGenerator<T> : GeneratorType, SequenceType {
let getNext: T -> T?
var current: T!
init(first: T, getNext: T -> T?) {
self.getNext = getNext
self.current = first
}
mutating func next() -> T? {
defer {
if current != nil {
current = getNext(current)
}
}
return current
}
}
for parentView in CStyleGenerator(first: view, getNext: { $0.parent }) {
// Do stuff with parentView
}
Correct but too-late answer: there are built-in functions in Swift 3 which provide the solution:
public func sequence<T>(first: T, next: (T) -> T?) -> UnfoldSequence<T, (T?, Bool)>
public func sequence<T, State>(state: State, next: (inout State) -> T?) -> UnfoldSequence<T, State>
We can use them in this manner:
sequence(first: view, next: {
// do something with $0...
return $0.superview
})
For instance
for view in views where view.superview != nil {
}

Resources