Check out a free preview of the full Polyglot Programming: TypeScript, Go, & Rust course:
The "Projector Object in Rust: Config & PWD" Lesson is part of the full, Polyglot Programming: TypeScript, Go, & Rust course featured in this preview video. Here's what you'd learn in this lesson:

ThePrimeagen walks through implementing the present working directory and config for the Rust version of the Projector object.

Get Unlimited Access Now

Transcript from the "Projector Object in Rust: Config & PWD" Lesson

[00:00:00]
>> So now we need to get the other parts of it, right, we need the present working directory. And we also need the config. So these should hopefully be pretty easy to code up. So let's go function, get config, and we're gonna take in a, instead of taking in the ops object, we're just going to take in, lets just take in the option to a file buff or a path buff that is a part of our struct.

[00:00:25] And the reason being remember with Rust when you pass an object, you don't get it back. So we gonna think a little bit more about what we have available. So let's go like this, config which is gonna be an option of file or file path buff awesome. So I'm gonna go all the way up here, where are you?

[00:00:44] There you're, that's what you are, and we're gonna return back out a path buff, awesome. So exact same thing we're supposed to do if let some, we'll just call this V for value equals config, so if it is if you've provided me one then I'm just simply gonna return that one, right?

[00:01:02] I'm just gonna echo right back out to you, return V, right? Fantastic, but if you didn't provide me one I now need to go out and do the exact same thing I didn't note. So we can go back and we can look at node for just one quick second.

[00:01:18] Where did we do this? We did this right here, right? I grabbed something from the environment I just said hey what's your config home, right? So we can do almost this exact that same thing right here, right? So, I'm gonna jump back using effectively that code up [SOUND] There we go, right?

[00:01:35] Look at that we have pretty much the exact same code right here. So how do we translate this in the Rust world? Everything is a lead, right? This is a constant, and instead of using process we go standard. And var right? And so, now I can just simply take in this beautiful little item right here, right?

[00:01:53] So there we go, we have this nice location. So what is this? Well, let's first go in here and let's kinda jump to this thing. And of course, the jump to definition awesome, it's working. So it actually returns a result of string, or there's a VAR error. So this is good to know.

[00:02:09] So that means if we take advantage of the error throwing stuff, and anyhow we can make this function really, really nice. Yeah, we have a question.
>> Can you get rid of the length check because of the pop expect?
>> No, we can't get rid of that because you could always provide more arguments here.

[00:02:29] I could provide two arguments to print. And so pop would actually pop off the second argument. It might be a bit confusing, we definitely got to keep that right there. So I'm using the exact same stuff right here we have our location, we have an error. So instead of returning a pathBuff, let's return an anyhow result and this is where the magic really happens with Rust and its error handling.

[00:02:50] So the exact same error handling was on the other side of go,right? We had every single line with if error not equal to nil do this. Now we don't have to worry about that. Since I've just returned this into a result, we have to turn it into an okay now.

[00:03:06] So, hey this function did not fail and I can just do this beautiful thing and now the word context. Now context allows me to add a little bit of information to the air, not like an expect. When an expect fails your program fails. Context on the other hand is when an error happens, I can just add some words to it and then somewhere else the program can fail or give me that information.

[00:03:27] So, I'm just gonna do that right here. Unable to get xtg_config_home, yeah, awesome, and then I'm gonna give it the old gUiw, beautiful little vim command right there. And then toss on the end, a wonderful little question mark. Now, what that question mark does is it unwraps the result, we already went through that.

[00:03:52] It doesn't match on the result, and if there was an air, returns the air. If there's not an air just gives me up the value. And look at that we now have the string so fantastic, right? So I'm just gonna use this and the promise is we have a string here.

[00:04:08] We don't want a string right we want a path buff, so let's do this let Lok equals path buff From Oak. All right, so now what does it look it's a path buff. Awesome, we have exactly what we want. And so we're gonna make it mutable path buff because we want to do a couple operations on it.

[00:04:27] Let's go loc.push, and I'm wanna push in projector. And then I'm gonna push in projector.json. So this is exactly kind of what you would expect from xtg.config.home. So I'm kind of using this method I'm not concerned too much about home anymore just like I wasn't on go we're just going to kind of stick to one of them you can pick one of them.

[00:04:50] However you want to but there you go, I now have my location pretty good, right? And so now I just need the return and Ok(loc) fantastic. We've just done it and it really made that error handling right here pretty dang easy I could make it a little bit more readable throw that right there awesome.

[00:05:09] I'm gonna copy this entire thing. Go down here and we're gonna do one more function, get present working directory. And again, remember with Rust, we wanna pass in the value we want to use. We don't want to just pass in the entire config or the entire options because then we run into this huge problem, with me converting one thing from a vector, and me having these references, and now I'm using this and this, and we got problems.

[00:05:37] So let's just stick with this because or else we don't want to clone out. So they will make more sense, the more you play with rest, sticking with values and using them. So let's go let's do what do we do right here? That's right, we did a present working directory and did this as an option of a path buff, right?

[00:05:57] And let's have the exact same thing, cuz how much do you wanna bet that present working directory might throw an error? So I'm just gonna pre assume that it is and I'm gonna return out a path buff, all right? If present working directory, we can also do is_some and then unwrap it, but might as well use pattern matching, right?

[00:06:17] Present working directory,return some present working directory, right? If it is some, awesome, let's return it. If it's not some, let's do something different. Let's do exactly this stuff, but how do we do present working directory? Well, how much do you wanna bet? There's yet another one of these type of things that exist.

[00:06:42] Now I'm not 100% sure if this thing exists but let's figure this out. So let's go to the standard let's go to end. And I bet you there is current dir. There you go that's the one the current directory it's in a path buff awesome but it does have an error.

[00:06:59] So, I'm happy that we did put this on here, so let's execute that. Let's put a nice little bit of context on this and went aired getting current directory I look nice that is we add a little bit of context for our future selves, right? Let's see present working directory equals that So what is present working directory?

[00:07:21] It is a path buff, awesome. Which means we can really just simply, we can just return this out, right? No need to do anything, else we got exactly what we wanted to get, fantastic. Let's just use that. And, of course, it's okay It's not some, we're not using options we're using results.

[00:07:40] My fault on that one. There we go, so we now have everything we kind of want. And so now we should just be able to build that simple method, to be able to convert a opt into a config. So let's do that. So we have a couple of different ways we can do that.

[00:07:58] We can either do a function that exists a public function that's like git config and you pass in an option. Or the options from those CLI, or we could just do an intel, intel is are pretty fun. I like those, so let's do a let's I'm gonna put it way up here, cuz it just feels weird being down there, right?

[00:08:16] And we also haven't even described it yet. Let's do a struct config. We haven't, we haven't even done that yet. How'd you guys forget, operation: which is gonna be, a present working directory, which is gonna be a pathBuff, and a config which is gonna be a pathBuff. Remember, we do need to make these public, so, don't forget to make things public, cuz we need someone to be able to import all this information in and to be able to use all these properties.

[00:08:48] And so now we can do our final little bit, which is gonna say, impl From. Actually, we're gonna wanna do a TryFrom, right? TryFrom a Opts for config. All right, so we're gonna convert our options into a config fantastic. This should be pretty easy to do again implement the members we get our type err and we have retry for a method.

[00:09:12] Well let's do that let's go and anyhow air. Hopefully none of this is too surprising. Ooh, love Ws. Didn't quite make it out of insert mode. There we go, we have it. Now we have the value that's ops again. What is happening to the ops right here? It's being consumed, right?

[00:09:31] So that means our main program cannot reference Opts after we pass it into this TryFrom. That makes sense though, we don't really need it again. I think we're all okay with that. Again, don't need that air because we're gonna be using the anyhow results type. It's just a simple shorthand.

[00:09:47] You can redefine things, you can effectively do these like little type redefinitions, right? So I can go foo equals a result of you usize that, right? And you're like, Cool. So now if I were to refer to foo, it has a specific value, right? So that's all that any house really doing underneath the hood if you're wondering why their result only takes in one value.

[00:10:07] They just defined the air, to be a special type of air. So that they can handle. All right, awesome. So we have this try from and now we just need to convert this one thing at a time. So let's do all the fun stuff. Value we do have is it args?

[00:10:22] Yep, we have this nice beautiful vector string right here. And now I can call try into, right? And I can go let operation equals this and do one of those fantastic. We have the operation because we already defined how it does its morphing and everything down below. Fantastic I can go config because I'm gonna go valued I'm gonna go get config So from of course value.config fantastic.

[00:10:55] And of course present working directory for present working directory, right? We have all three of those, now I could have in lined each one of these when I created the struct. But I just kinda wanna throw it out here so you could see each step. But in the reality is I could have just done a simple one of these and just had them nicely defined in here, right?

[00:11:15] I could just move them all down in here, but we'll do operation, config, present working directory. And of course it's gonna say hey you're wrong I expect a result object, If you're absolutely right, let me give you that result object. Okay, boom, and this thing has mismatch thing.

[00:11:32] I forgot to do. [LAUGH] It's not funny. It's not funny at all. There we go, nice error handling it feels very simple, it just passes this up the chain. Does this all feel pretty good, the air handling.I know you guys are probably rapidly typing trying to keep up.

[00:11:51] It's very familiar for me, so it feels very easy to do. I know it feels foreign for you, it's like the first time seeing a lot of these kinda concepts, but it becomes progressively easier. You just little bit of time always makes things easier. Does this all make sense is everyone kind of on the same board with this does that make sense what just happened there.

[00:12:12] What about this? Try_into, do you like that? What happened when I did that try_into? Does anyone know? How did it know what it was? Or two things happened, right? Well first off, how did I use operation? I used operation down here and config. So knew for a fact it was of type operation.

[00:12:36] Second, what is try into? Try into is a method that exists if you implement the try from trait. So when I go down here and I had this nice little try from trait right here I said hey if you're a vector string and I called try into you can become an operation if you need to become an operation.

[00:12:53] And so that's how it was able to do all those transformations the compiler figured it out, from how I used to Operation what needs to happen. So it's pretty clever, pretty awesome and knows exactly where to call it and now all the airs are nicely flowing through. And so when we go to our main file, what do we call it, projector.rs.

[00:13:13] I can then, I can like this config. Up, I probably need to import in config and I can go try into do one of those beautiful little things right there. And then of course I need to return a result of nothing, right? Cuz we don't do anything out of the main function so I'm gonna do this nice little okay over here, and of course it's gonna say I don't know what this result is, right?

[00:13:39] I don't recognize it anyhow use anyhow result. And then I got this really beautiful nice little thing that worked all the way through except for the darn debug which I forgot. So of course do the old derive debug and then it's gonna say well I don't know if you know this but operation doesn't do debug.

[00:14:03] Okay, so that's pretty rude and so we're gonna throw that on there since all the subtypes and operation do derive debug we should be good to go jump back to our main file and as you can see everything's working let's go cargo run blah. Blah, blah, blah, blah, blah and it's gonna say your print is wrong you gave me two again but I expected one so it all worked out in the end.

[00:14:23] I hope it's not too overwhelming is kind of an ambitious project cuz I do a lot of these three languages on Twitch and for YouTube. And I don't wanna overwhelm because they all feel more trivial to me because I do them a lot. But I feel like I had to learn rust by doing things reading things and doing it a bunch over time.

[00:14:43] But if I could have just saw someone one to one translate something really fast. I feel like that would have been I would have been like, okay? Yeah, this makes more sense. Okay, but the hard part I think about rust is just, knowing more about what traits are available.

[00:14:57] A lot of what makes something idiomatic is just knowing what is available. And I feel like that's just a function of time. And how good you are at reading documentation and remembering specific things and how to use them.