Polyglot Programming: TypeScript, Go, & Rust Process CLI Args in Rust
Transcript from the "Process CLI Args in Rust" Lesson
>> So we can now, I'd say we're done here, this is fantastic. We're blazing through these programs, it's almost like the pre-planned. And so let's do the Rust version. Is everyone ready to do the Rust version? Awesome, I'm very excited about this because, man, this is gonna just blow your mind.
[00:00:15] At least I feel like it blew my mind and it was awesome. All right, so let's go to Rust projects. And of course, we have these in our bin file, so that's okay, we can keep them there, we don't really care. So right now we're inside of our source folder, right?
[00:00:28] So everyone's still using the previous one, we're inside the source folder. So let's create a lib.rs as the first thing we're gonna do. Now remember, I told you this is where we actually put all the files that we want to use inside of our library. The name of our library depends, of course, on where and how we did cargo in it.
[00:00:46] You can change the things, but for us its literal name is just Rust right now because we created it in a folder called rust, right, fantastic. Now, we're gonna do one thing that has screwed me up many times in the past. We're gonna go like this, cargo add clap, see I don't even have it.
[00:01:04] So that means if I mistyped this, we'll be sitting here debugging for five minutes because it's terrible. So there's this idea of feature flags in Rust where you can actually, it's kinda like a C preprocessor macro where you're able to remove out sets of code so it's not compiled in.
[00:01:19] Rust has the same idea, except for they call them feature flags. And so for this one specifically, it's called derive, if I'm not mistaken. I bet you I have it on the Rust side of things. Just because it's, by the way, I'm still using all these things. So there you go.
[00:01:36] features=derive, just as we thought, right? Cannot forget that, Holy cow. Whenever you're using Rust, just like a little fun thing. So if I go like this rustlang clap, right? I go here and I go to the docs, always check the feature flags right here. This is gonna give you that information off the rip that you're gonna be like, my goodness.
[00:01:57] Because if you didn't know about derive, it's gonna give you this clap derive, and it's emotionally painful when your stuff is not working, all the example says it works. And it's just like that stuff doesn't exist. And so if you ever run into that, look at the feature flags, make sure you have them enabled, cuz that's likely why your stuff doesn't exist.
[00:02:17] I mean, it's great but it's also emotionally painful when you run into it. All right, let's see, okay, let's see. Okay, we already have all that. I just wanna make sure we don't have any option. Okay, I don't wanna show you guys anything yet. All right, so let's do the exact same thing.
[00:02:30] Let's hit Enter, let's install it. It should take a moment. Apparently all of those things happen, I don't know what exactly happened there. Let's see, no. And so you should see in your cargo.toml that you now have a dependency on both anyhow and clap, if you're still using the same Rust project we were using earlier.
[00:02:47] If you don't, you can always throw in anyhow right now if you'd like to, that's fine. We'll be using it here in a little bit. So now let's go back to our lib.rs, I'm gonna save this out right here, and I'm just gonna like this, pub mod opts.
[00:02:59] And then I'm gonna go in here and create opts.rs. And then it's gonna say for a moment, file not included in module tree. That means this thing just doesn't exist within your project. And so your lib.rs needs to make sure that it's updated. I'm sure as things go, you'll see that it'll disappear here shortly.
[00:03:18] And then let's create one more file. Let's create projector.rs inside of our bin folder. So this is our main entry point. So let's go fn main(), there we go. So we have our main, awesome. When we call --bin projector, this is hopefully the function that will be executing right here, most excellent.
[00:03:39] So let's go back to this, awesome. My LSP is now called back up, I can jump to the file. Everything's there, so my stall tactic actually worked quite well. Let's do this, so remember how we had these structures that existed, right? So we could do struct Opts, and if I could just build it, I would build it using this.
[00:03:58] I'm gonna go, well, I want an args, right? But we don't need to make a clap like that. So I'm just gonna go like this, pub args, and I want this thing to be a vector of string, right? That makes sense. That's one of the things we want inside of our structure.
[00:04:11] A vector of string, of course, is the same thing as a string list in Golang or TypeScript. After that, we're gonna want a config, and now normally it'd be something like this, OptionString is probably what you're thinking of, something we're grabbing from the command line, but it's not.
[00:04:28] We're gonna use OptionPathBuf. So this is one of the claimed fames for why Rust is better. Is that you may not know this, but paths aren't necessarily UTF-8. So there are a certain set of paths in which can break Go because you've broken a UTF-8 string and so can't do that.
[00:04:49] So, all of that, so super superior, there we go. And we can also do this, right? You may or may not provide me a present working directory. You may or may not provide me a config, and there will just be a list of strings. Now, obviously, we could technically wrap this with an option of Vec, but if we did this, it would tell us as we're using clap, option of Vec is kind of redundant because an empty vector is already telling you it's empty, why would you want even more signals that it's not there?
[00:05:21] So we'll do that, and now let's start using clap. So clap comes with a couple things, I've noticed that I've just had a really hard time getting the ELCP to autocomplete for me on this one. So what I'm gonna do is I'm gonna do like this, derive, and I'm gonna do Parser.
[00:05:35] Now, it's gonna say, I don't know what Parser is, and you're gonna try to include it. Nice, it worked this time. There you go, you can see Import 'clap::Parser'. So make sure you get this from clap::Parser, this is really, really good. After that, I'm gonna just type in the word clap.
[00:05:50] And this is gonna give us all sorts of great stuff right here. And then I also need to do a little pub right here, and now we need to kind of take each one of our properties and do something to it, right? So one thing I wanna do is I'm gonna take this config right here and I'm gonna go clap and I'm gonna type in short = c, long = config.
[00:06:18] Take that out, there we go. And I'm gonna do the exact same thing right here. Oop, I think I need to reverse those. Why is it saying proc macro not expanded? I have never seen that error before. All right, let's just keep on going, we'll see what happens as we compile it.
[00:06:37] Maybe who knows what's happening there? All right, last one is present working directory. And so there we go, we're deriving our parser. We have our clap, we have our opts, we have our config, we have this, we've kinda just defined it on a structure, which is kinda nice to be able to have that.
[00:06:55] So we need no function to parse this because clap does the parsing for us and it'll just put it inside this opts structure. So let's jump back into this and go Opts, which should show up, which it's not. So remember, the name of our project, I believe was rust.
[00:07:10] My goodness, I've just had the greatest time with, The LSP working. And it's gonna say, hey, can't find this method, why? Well, remember how traits exist, traits are things that you can implement. Rust isn't able to tell what traits this object implements if the traits are not in scope.
[00:07:36] So, that's why it's saying, hey, there's no function called parse on this thing. So if I implement or if I use clap::Parser, that should bring it about and nowit can tell, hey, you have this. Now it's like, okay, I can see this trait. I see what method this has, your opts implements this, awesome.
[00:07:59] Let's do that, so let's go println, I'm gonna print out the opts just, so we can all see it happening. And let's also do the guy smoking a pipe. We don't implement debugs, so let's just jump over here and implement debug really quickly. There must be something wrong because I'm not getting any autocomplete.
[00:08:19] All right, cargo build, let's see, I'm just gonna execute the cargo build, make sure everything builds. It's like, hey, everything built, right? Cargo run --bin projector, there we go. Okay, everything runs, I don't know what's going on with my LSP, something must be going crazy. So let's just try a couple items.
[00:08:39] Let's try foo, awesome, bar, awesome. Exactly what we wanted, path/to/thing, great. So, you can see, it went from a none value to a some value. So this is everything we kind of wanted right here, right? We now have this nice kind of arg parsing. Out of all three of them, which kinda feels like the easiest parsing of the CLI options?
>> Yeah, it's a sweet macro system, whatever is going on, it is awesome. I wish I understood why my LSP was breaking so often cuz I feel like it's even better especially if you don't, I mean, look at those. It looks terrible. Here, I'll reopen it back up just in case.
[00:09:20] And so quite nice, right? It is really, really nice to be able to have something like that, and that's actually one of the reasons why just [LAUGH] I absolutely just love Rust, it's these procedural macros, right? These proc macros just allow for code to be generated, that is kind of complex, but it feels very simple to you.
[00:09:38] You can just go, yeah, okay, I just defined them right here. Everything's beautiful, awesome. And so there we go, we now have the options. Let's see if at least my LSP is sort of working. Let opts = Opts, yay. Okay, at least that's working still, okay, fantastic. So we got this.
[00:09:57] So we can now move on to the next stage. Is there any questions while we're here, cuz we kind of did the whole thing? Here's what I said we should do, nice. It's identical, right, I put these in different order. I can even put a default value in there if you really want to.
[00:10:12] It looks like you don't have to.
>> On your main, for example, you have to declare the use of every library you use so that if you have like-
>> Yeah, right here, you're talking about this thing right here.
>> Yeah, so if you were using a bunch of different files that use different libraries, you have to use them all here?
>> So each file can import what they need. And so you only import kind of what you need, if anything is not used, it will let you know. And so if opts relies on something that you don't need to rely on, you can see right away that if I go back to Opts, it relies on PathBuf, right?
[00:10:48] I have no mention of PathBuf in here. So it's just like Node or just like any other module system, each file just has its own right to be able to do that.