Transcript from the "Using the Projector CLI in Rust" Lesson
>> We have now crushed out go. So let's move on to rust, right? Very excited about this. It's the final moments man. All right, so ,let's go to bin projector, so that's where we're gonna go. I would've used a sweet, sweet harpoon to jump there, but I feel like that might be a bit disorienting, for you guys to see that, yes, that was a self promotion, harpoon greatest plug I ever written, there we go.
[00:00:31] So, source bin projector, right? Now all we have is a config. So now we need to create the projector, right? Let projector equals well how do we do this one again? I can't quite remember. Did we do a new projector? So what did we do? Was the way we decided to create it, from config.
[00:00:55] Okay so we're having it as a static method let's use that from config, so first we need to import it from config right here. So it's gonna take in our opts, which is terribly named. Let's rename that from opts to config, fantastic. There we go, we have our projector.
[00:01:17] Now all we need to do, is go through each one of the operations, we should do that. So we should use the match operator because now we can do all those sweet pattern matches, which I'm very, very excited about. So, let's go config, let's go operation and let's match on missing arm.
[00:01:33] Okay, let's fix up the arms. So, we have an operation. Can we just get it to, there we go, and let's do print. And let's we can deal with just the none arm. Now that's actually pretty cool because now our good value is this, right? That's exactly what we wanted to see.
[00:01:50] I really liked that. It makes it feel so much better. Let's just hop back for one quick second to our other one. Notice that on our other one, what do we have to do? We had to, if it is a print and there's nothing there, then we do this, else we got to do that, whereas in this one it's very specific.
[00:02:07] When it's this one it's this type, I operate like this. I think that's just really clean, really appreciative. And so that means I can also do print some value, right? So now we also have the value that we're gonna be doing something with. Awesome, let's do it again, let's also have Add which is gonna have key and value.
[00:02:29] And then of course, ensure all possible, yep. And then we also need remove, which is just key. Fantastic, well, we have it, but I want you to notice something. There is an error cropping up that doesn't look like an error I was expecting. So what is this error?
[00:02:44] This error of course is unused variable. We should prefix it and then use have moved value. No, the borrow checker. It's ready, it's hurting our feelings. What happened here? Why are we running into this? Well, this is why, we pass the config in, what happens if we are the value owner and we hand the value to a function, who owns the value.
[00:03:13] We don't own the value anymore, it's been moved out of our hands, so how could we possibly ever access this value again, it's gone, it's not ours. So that is what just happened there. We moved it all the way to the projector, which means unfortunately, all of our great ideas to make these three programs identical, actually have just completely fallen flat.
[00:03:33] And now we need to do a bit of a refactor, don't we? Yeah, it hurts. So we could just clone it if we were lazy, but we're not lazy here, people. Besides that other time we were lazy, we are gonna be really non lazy here. We're gonna actually do the right thing here.
[00:03:47] So, to me, what are we even using inside this config object? Well, we need a reference to some contents that required a reference to the config path, okay? That's not that bad, right? What else do we need? I guess on the projector itself, we need to present working directory.
[00:04:10] And then we also need that same config path such that we can save this thing off again, correct? Yeah, but do we need the operation? Now we don't need the operation. The projector itself does not run the operation, it's the outside of the file that runs the operation, therefore, we should just be able to kind of reduce what we pass in here and just let it only use a certain amount of items.
[00:04:33] So let's try this out. Let's go in here and let's change this up a little bit. Let's change config to a path buff and let's change present working directory to a path buff and get a couple errors, just Rust analyzer still trying to assert itself. We obviously dominated it and so now we can go here and we can erase this or still gonna want to use this whole referencing thing right here.
[00:04:57] But, this is wrong, right? So now let's do a slight refactor, jump up here. And let's have config be a path buff, and also a present working directory, jump back here. And now we also need the present working directory to present working directory, beautiful present working directory again, beautiful.
[00:05:18] Now our projector is mostly fixed except for all the references that we have to config in which we do config.pwd or config.config. So let's go config slash that. And so I can just delete that, right? I don't need that cuz now, look at this, it works, right? All right, awesome, do it again, there's our shame right there.
[00:05:39] The shame is so painful. All right, there we go. We don't have any other references right here. We have a small little error right here. This is a highlighting error. All it's saying is, hey, that associated function defined here. You're like, wow, that's an amazing diagnostic. I'm really happy that I read that, I know exactly what that means.
[00:05:57] What this means when you see this just means that there's an error somewhere else in which this is kind of like the root cause of the problem. So, of course, if we go back here, you can see right here, that's the root cause of the problem. So what I'm gonna do, is I'm gonna take my beautiful config, and I'm gonna move the config and the present working directory into that function.
[00:06:17] Now I still own the config myself, I at least own the operation. I moved out the other two parts, I have that. I do not believe that I should be able to go and do, if config.pwd equals let's see PathBuf from that, it's going to complain about some things here.
[00:06:41] I'm just going to make it happen, right? Sorry that value has already been moved, you've used it, it's gone, stop touching it. Awesome, so I'm gonna remove that. There we go, we did our small refactor, everything appears to keep working, just to make sure we can run a quick cargo test.
[00:06:58] My goodness, we have a couple of small little errors of course because that's how we are creating our projector. So let's go back to projector and go down to the bottom and go right here. Obviously, we're creating a projector using a config, we actually don't even need to do that anymore.
[00:07:12] We can just simply take that. And of course do a present working directory. Boom, our life has been resolved. Awesome, we had some warnings. We'll deal with those warnings at some points because they are currently in our main file all right here. Awesome, so we've done it. We have created everything back to it, we have avoided the borrow checker problem.
[00:07:35] We can now hopefully next time if you're programming something for whatever reason the same thing and two different language, you can see it coming. Cuz you like, yes, the moving, early I was hoping that this is kinda like the thing that really sets in Rust. And why you need to think about your types a little bit more, why values are very important to understand what happened.
[00:07:53] So, now that we have that let's just do the printing, right? So if we have none, we need to get them all, we need to print them. So let's go like this const wrong language. Asserting that we know TypeScript just for a moment. So let's have the value that comes out of the proj.get_value_all, right?
[00:08:11] So of course, what is this thing? Is a reference or it is a HashMap of reference string. And we should just be able to simply encode that, right? So we can go serde- json to string. And we're not going to do pretty we don't want anything pretty about this, but of course what comes out of this thing, an error.
[00:08:34] So we should probably start handling errors, look at that we already did handle the error, we haven't anyhow error, already coming out we can use, anyhow, this is fantastic. So, just throwing a little question mark there, and I'll reassign value. So value goes from a hash map string into a string.
[00:08:49] Fantastic, transfer that and then do a beautiful println bang, and do that value. Look at that, what's the last thing? Consider a borrow, of course, awesome, we've done it. We've now borrowed out that, cuz remember Serde Json does not need the type itself, or it does not need the value itself.
[00:09:10] It just needs the reference to the value to read adult and produce the JSON, fantastic, look at what we have done. We have done amazing things here. And I also really liked this because, again, there's no if elses here. We're working on types, it makes it beautiful. So, let's do a get_value and we'll pass in v, which really should be renamed k, get that and of course what happens with k, well k is a map and so what does that mean?
[00:09:40] That means we don't know if it exists, right? So let's use a beautiful and then, right. And so we can use an and then or we can use a map, if we wanted to do something, right? So maps pretty good one, we can actually just use this as I'm add things.
[00:09:54] It's pretty great. We can just provide a simple function that takes this and does something with it, right? So what does it need to do with it? Well, we really just need to go in here and doesn't print that thing out. Do we not? Yeah, it's fantastic. And of course, we need to just borrow okay.
[00:10:10] Well that, was printed it out, that's all we did. It's beautiful, right? I like it, all right. So now we need to do the adding, so what is adding of course, well it's projector set value Passing the k, pass and the v and all that's pretty much it but no it's not mutable, classic blunder thrown the mute, do that, we'll do them.
[00:10:38] For both of these, we need to do a save just like before, pretty much everything else is kind of just moving by motions now. I'm gonna throw on a question mark cuz know for a fact it's gonna return a result object, let's make sure that it throws an error if things aren't successful, do the exact same thing here.
[00:10:54] Let's do a remove value, only it's passing the k and of course it wants to borrow it. All right, beautiful, We're pretty much 99.5% done. If you consider this last thing, 0.5% in complexity. All right, save my guess let's just do a result of nothing, return, okay. Yes, I still use explicit returns during the entire duration of this course.
[00:11:17] So, all we have to do now is import anyhow because this thing saying this does not exist, you need two types on here, use anyhow result little bit of even now, that was intentional. There we go, so we have the anyhow result fantastic. We just simply have to go, does the thing exists right?
[00:11:39] We've done this so many times now, it should almost feel monotonous. All right so let's go dir and we're gonna need a reference to self, does not need to be mutable because we're not actually changing any data, right? So you can go self.data or not data, they config path, right?
[00:11:58] So now that we have that, now we can technically do parent, to get rid of what's currently there. That is one way in which we can do that. And so we're gonna just try this out, right? that that seems fairly sensible. And we'll do a little if some path equals this, so we're gonna just grab the value out, forgot the let.
[00:12:27] Awesome so this will just represent our dirname at this point. So all we need to do is just make sure that this thing exists. Again we did this earlier right down here, right? We do this whole metadata call is okay, if it's not okay, then we clearly need to do something with it, right?
[00:12:43] So if this path is not okay, then we need to do a creation of it. So I believe it's an fs that there's some sort of maker, okay, wrong one creator.all recursively creates the directories. There we go, that's the one we're looking for. So let's do it. And let's pass in the p and of course, we're not handling the result.
[00:13:08] So awesome, we were correct, great assumption from everybody in the class. Make sure we always use a result object. Perfect, we can just hit it with the question mark, return it if it's bad and now, oops, I just may have deleted something. I'm not exactly sure. No, I don't think I did.
[00:13:25] All right, awesome. So now all we have to do, is just write the file out. So let's go std::fs::write, and this will write a slice as the entire contents of a file. Perfect, documentation in hand makes life a lot easier. Let's use simply the past self config and of course the contents.
[00:13:43] What is the contents? Well, it's gonna be the JSON encoded stuff. So again, much like go, we have to do this kind of dance, right? So I'm gonna grab the contents, let contents = serde_json to string self data, right? And throw in one of those, so why does this work so well?
[00:14:04] Well again, we added the serialize, deserialize. So everything just works behind the hood. We don't even have to know what's going on. Awesome, and then of course throw in the contents. This thing is probably gonna say, hey, use this whole borrowing thing, and we have results that are unused.
[00:14:20] Fantastic, again you should see it, I mean this should make sense you should be able to reason about this now. Especially now that we've had these value issues come up. Why would I need to give this thing the value? I should just give it a reference, it can read the reference, it doesn't need to do anything with the reference, it doesn't need to store the reference.
[00:14:35] It just needs it while it's doing the single operation. So hopefully now this makes a lot more sense why sometimes you'll see me throwing out an ampersand sign because we've now experienced the full Baro checkers evil and how painful it can be, fantastic. We've done it. We've written save.
[00:14:52] I think we've done everything. Once again, just let's just do like a quick cargo build. [SOUND] All right, let's find out. Did we do this one, first try. So of course, let's go here, let's go projector config. Let's use our present working directory again. And let's call it conf.json.
[00:15:14] And let's just do an empty one. Of course, what do we get? Well, it says you can't do that. It's very, very smart. So, in a lot of CLI programs, you have to do this double dash, which means that the parser will quit parsing at that point. And all further things will be passed into the child program that's being ran.
[00:15:29] Because obviously we're not running cargo. We're actually running the binary projector, so there we go. It printed out this beautiful empty object along with a bunch of it, warnings we're gonna ignore the warnings. And so now we can go like this, a foo, nothing, awesome. I mean now I kind of want to get rid of them.
[00:15:48] Cargo clean, can we do that? Cargo, I think it's fix, right? Is it fix? There's like this thing that will remove all the warnings. You have to do dash dash dirty. But my guess is it's, I didn't do the right thing. Let's see. Okay, thank you for all that.
[00:16:10] All right, so let's run this thing. Perfect, it didn't print anything out, awesome. Let's try to do add foo bar. So we've added foo bar. And now let's try again and let's look at foo. There it is. It's beautiful. It's wonderful. It's fantastic. Let's take std error and redirect it to dev, null.
[00:16:33] And now look it's just bar, it's fantastic. It's beautiful, all right. I feel I already said that