{"id":5812,"date":"2021-03-31T07:00:43","date_gmt":"2021-03-31T14:00:43","guid":{"rendered":"http:\/\/writeasync.net\/?p=5812"},"modified":"2021-03-29T19:44:49","modified_gmt":"2021-03-30T02:44:49","slug":"letter-boxed-rust-impl-part-1","status":"publish","type":"post","link":"http:\/\/writeasync.net\/?p=5812","title":{"rendered":"Letter Boxed: Rust impl, part 1 (basics)"},"content":{"rendered":"<p>We&#8217;ve already <a href=\"http:\/\/writeasync.net\/?p=5808\">set up the development environment<\/a>, so let&#8217;s write some Rust code!<\/p>\n<p>A good place to start is with the bottom layer data structures, known as <a href=\"https:\/\/github.com\/brian-dot-net\/games\/blob\/master\/src\/Words.Core\/Str.cs\">Str<\/a> and <a href=\"https:\/\/github.com\/brian-dot-net\/games\/blob\/master\/src\/Words.Core\/Ch.cs\">Ch<\/a> in the C# version. To review, <code>Ch<\/code> is an enumeration representing the characters A-Z (and a <code>None<\/code> value == 0), while <code>Str<\/code> packs up to 12 <code>Ch<\/code> values into 5-bit chunks plus a 4-bit length for a total of 64 bits. Already we have one small point of contention, in that Rust has a very similarly named primitive <a href=\"https:\/\/doc.rust-lang.org\/std\/primitive.str.html\">string slice type called <code>str<\/code><\/a>. To make things a bit less confusing, we can use the name <code>St<\/code> here instead.<\/p>\n<p>Going test first, we will begin by translating the following C# unit test into Rust:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n        &#x5B;Fact]\r\n        public void Empty()\r\n        {\r\n            Str s = default(Str);\r\n\r\n            s.Length.Should().Be(0);\r\n            s.ToString().Should().Be(string.Empty);\r\n            Enumerable.Range(0, 12).Select(i =&gt; s&#x5B;i]).Should().BeEquivalentTo(\r\n                Ch.None,\r\n                Ch.None,\r\n                Ch.None,\r\n                Ch.None,\r\n                Ch.None,\r\n                Ch.None,\r\n                Ch.None,\r\n                Ch.None,\r\n                Ch.None,\r\n                Ch.None,\r\n                Ch.None,\r\n                Ch.None);\r\n        }\r\n<\/pre>\n<p>Here is one possible reimagining:<\/p>\n<pre class=\"brush: rust; title: ; notranslate\" title=\"\">\r\n    #&#x5B;test]\r\n    fn empty() {\r\n        let s = St::empty();\r\n\r\n        assert_eq!(0, s.len());\r\n        assert_eq!(&quot;&quot;, s.to_string());\r\n        let expected = vec!&#x5B;\r\n            Ch::None,\r\n            Ch::None,\r\n            Ch::None,\r\n            Ch::None,\r\n            Ch::None,\r\n            Ch::None,\r\n            Ch::None,\r\n            Ch::None,\r\n            Ch::None,\r\n            Ch::None,\r\n            Ch::None,\r\n            Ch::None,\r\n        ];\r\n        let actual: Vec&lt;Ch&gt; = (0..12).map(|i| s&#x5B;i]).collect();\r\n        assert_eq!(expected, actual);\r\n    }\r\n<\/pre>\n<p>This already gives us a lot to chew on. Going line by line, let&#8217;s dive into the details. First, we assign an empty string value using an <a href=\"https:\/\/doc.rust-lang.org\/reference\/items\/associated-items.html#associated-functions-and-methods\">associated function<\/a> (acting as our <a href=\"https:\/\/matklad.github.io\/2019\/07\/16\/perils-of-constructors.html\">constructor<\/a>) of the <code>St<\/code> struct. Then we ensure the <code>len()<\/code> and <code>to_string()<\/code> functions return sensible values (0 and empty string, respectively). At the end, we prepare a <a href=\"https:\/\/doc.rust-lang.org\/stable\/rust-by-example\/std\/vec.html\"><code>Vec<\/code><\/a> of expected <code>Ch<\/code> values and use a <a href=\"https:\/\/github.com\/rustomax\/rust-iterators#basic-ranges\">range<\/a> to select (i.e. <a href=\"https:\/\/doc.rust-lang.org\/std\/iter\/trait.Iterator.html#method.map\">map<\/a>) each index of the <code>St<\/code> and collect this into an &#8220;actual&#8221; <code>Vec<\/code>, asserting that it has the right contents. Note that due to <a href=\"https:\/\/rustc-dev-guide.rust-lang.org\/type-inference.html\">Rust&#8217;s excellent type inference<\/a>, we only have to explicitly use a type for the result of <a href=\"https:\/\/doc.rust-lang.org\/std\/iter\/trait.Iterator.html#method.collect\">the <code>collect<\/code> method<\/a>.<\/p>\n<p>One possible implementation that satisfies this test is as follows:<\/p>\n<pre class=\"brush: rust; title: ; notranslate\" title=\"\">\r\nuse std::{\r\n    fmt::{Display, Formatter, Result},\r\n    ops::Index,\r\n};\r\n\r\n#&#x5B;derive(Clone, Copy, Debug, PartialEq)]\r\npub enum Ch {\r\n    None,\r\n}\r\n\r\npub struct St(u64);\r\n\r\nimpl St {\r\n    fn empty() -&gt; St {\r\n        St(0)\r\n    }\r\n\r\n    fn len(&amp;self) -&gt; u8 {\r\n        0\r\n    }\r\n}\r\n\r\nimpl Display for St {\r\n    fn fmt(&amp;self, f: &amp;mut Formatter) -&gt; Result {\r\n        write!(f, &quot;{}&quot;, &quot;&quot;)\r\n    }\r\n}\r\n\r\nimpl Index&lt;u8&gt; for St {\r\n    type Output = Ch;\r\n\r\n    fn index(&amp;self, _index: u8) -&gt; &amp;Self::Output {\r\n        &amp;Ch::None\r\n    }\r\n}\r\n<\/pre>\n<p>Again, we&#8217;ll just go through this line by line. The top section is the necessary <a href=\"https:\/\/doc.rust-lang.org\/stable\/rust-by-example\/mod\/use.html#the-use-declaration\">use declarations<\/a> to avoid having to fully qualify the various library type names that follow. Next, we have the <code>Ch<\/code> <a href=\"https:\/\/doc.rust-lang.org\/book\/ch06-01-defining-an-enum.html\">enumeration<\/a> which consists of a single member for now. It is annotated with a <a href=\"https:\/\/doc.rust-lang.org\/rust-by-example\/trait\/derive.html\">derive attribute<\/a> telling the compiler to produce default implementations of four traits (<a href=\"https:\/\/blog.rust-lang.org\/2015\/05\/11\/traits.html\">roughly equivalent to interfaces<\/a> in other languages). We want the <a href=\"https:\/\/riptutorial.com\/rust\/example\/15356\/ownership-and-the-copy-trait\">Copy trait<\/a> because we want to be able to freely pass <code>Ch<\/code> by value like any other primitive type. We also need <a href=\"https:\/\/doc.rust-lang.org\/std\/marker\/trait.Copy.html#whats-the-difference-between-copy-and-clone\">Clone as it is a super-trait of Copy<\/a> (which will implicitly reuse the &#8220;cheap&#8221; copy behavior in this case). <a href=\"https:\/\/doc.rust-lang.org\/rust-by-example\/hello\/print\/print_debug.html\">Debug is a nice-to-have trait<\/a> for most types, but we are actually forced to use it here because <a href=\"https:\/\/doc.rust-lang.org\/std\/macro.assert_eq.html\">assert macros require it<\/a> (e.g. in case they have to produce an error message). Similarly, we need <a href=\"https:\/\/doc.rust-lang.org\/std\/cmp\/trait.PartialEq.html#derivable\">PartialEq<\/a> since we can&#8217;t reasonably assert equality without it! We could have also used <a href=\"https:\/\/users.rust-lang.org\/t\/what-is-the-difference-between-eq-and-partialeq\/15751\">strong equivalence via Eq<\/a>, but for now we&#8217;re just doing the minimum necessary to pass the tests (or in this case, the compiler!).<\/p>\n<p>The rest is code for the <code>St<\/code> struct. We start with the definition which is just about the simplest <a href=\"https:\/\/learning-rust.github.io\/docs\/b2.structs.html#Tuple-structs\">tuple struct<\/a> you can create &#8212; a single 64-bit unsigned integer. Then we have the <a href=\"https:\/\/dev.to\/somedood\/generic-impl-blocks-are-kinda-like-macros-1aa0\">implementation block<\/a> with stubs for the <code>empty<\/code> and <code>len<\/code> functions. The last two blocks are <a href=\"https:\/\/doc.rust-lang.org\/book\/ch10-02-traits.html#implementing-a-trait-on-a-type\">trait implementations<\/a>. The first is for Display, which is roughly equivalent to <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.iformattable?view=net-5.0\">IFormattable in the .NET world<\/a> &#8212; this is what backs the <a href=\"https:\/\/doc.rust-lang.org\/std\/string\/trait.ToString.html\">to_string<\/a> method. The <code>fmt<\/code> function here is basically just boilerplate; we use a <a href=\"https:\/\/doc.rust-lang.org\/std\/fmt\/struct.Formatter.html\">Formatter<\/a> with the <a href=\"https:\/\/doc.rust-lang.org\/stable\/rust-by-example\/hello\/print\/fmt.html\">write macro and format string<\/a> to produce an empty string. Finally, we have a stub indexer implementation which enables us to use square brackets to return a <code>Ch<\/code> item (defined as an <a href=\"https:\/\/doc.rust-lang.org\/rust-by-example\/generics\/assoc_items\/types.html\">associated type<\/a>, similar to a <a href=\"https:\/\/stackoverflow.com\/questions\/759512\/internal-typedefs-in-c-good-style-or-bad-style\">class-level typedef in C++<\/a>). Rust doesn&#8217;t have direct <a href=\"https:\/\/doc.rust-lang.org\/rust-by-example\/trait\/ops.html\">operator overloading<\/a> as such, but achieves the same through the <a href=\"https:\/\/doc.rust-lang.org\/std\/ops\/index.html\">traits in std::ops<\/a>.<\/p>\n<p>The next test introduces the concept of appending a <code>Ch<\/code> to create a longer <code>St<\/code>:<\/p>\n<pre class=\"brush: rust; title: ; notranslate\" title=\"\">\r\n#&#x5B;test]\r\nfn one_char() {\r\n    let s = St::empty() + Ch::A;\r\n\r\n    assert_eq!(1, s.len());\r\n    assert_eq!(&quot;A&quot;, s.to_string());\r\n    let expected = vec!&#x5B;\r\n        Ch::A,\r\n        Ch::None,\r\n        Ch::None,\r\n        Ch::None,\r\n        Ch::None,\r\n        Ch::None,\r\n        Ch::None,\r\n        Ch::None,\r\n        Ch::None,\r\n        Ch::None,\r\n        Ch::None,\r\n        Ch::None,\r\n    ];\r\n    let actual: Vec&lt;Ch&gt; = (0..12).map(|i| s&#x5B;i]).collect();\r\n    assert_eq!(expected, actual);\r\n}\r\n<\/pre>\n<p>Here we use the + operator, which requires us to implement the <a href=\"https:\/\/doc.rust-lang.org\/std\/ops\/trait.Add.html\"><code>Add<\/code> trait<\/a> for <code>St<\/code>, as well as a Display implementation for <code>Ch<\/code> and more reasonable definitions for <code>len<\/code> and <code>fmt<\/code>: <a href=\"https:\/\/github.com\/brian-dot-net\/games\/commit\/434201fb89fc37334e6d74bf8852ff1667bb636d\">[see commit on GitHub]<\/a><\/p>\n<p>Once we get to the two character test case we end up with most of core implementation code: <a href=\"https:\/\/github.com\/brian-dot-net\/games\/commit\/7c56202f02856736267b46b4079f09984c514f20\">[see commit on GitHub]<\/a><\/p>\n<p>After that, it&#8217;s all pretty mechanical, culminating in the 12 character test (the maximum our <code>St<\/code> can hold) at which point all <code>Ch<\/code> values from A-Z are accounted for: <a href=\"https:\/\/github.com\/brian-dot-net\/games\/commit\/adb9f0b6efee0b8b26d2623fbfb7ee11db08ff9f\">[see commit on GitHub]<\/a><\/p>\n<p>While developing the above code, I benefited greatly from the <a href=\"https:\/\/rustc-dev-guide.rust-lang.org\/pat-exhaustive-checking.html\">exhaustiveness of the Rust match operator<\/a>. When adding new enum values, Rust could automatically tell me if I was missing any cases, e.g.:<\/p>\n<pre class=\"brush: rust; title: ; notranslate\" title=\"\">\r\nimpl Add&lt;Ch&gt; for St {\r\n    type Output = St;\r\n\r\n    fn add(self, rhs: Ch) -&gt; Self::Output {\r\n        let c = match rhs {\r\n            Ch::None =&gt; 0,\r\n            Ch::A =&gt; 1,\r\n            Ch::B =&gt; 2,\r\n            Ch::C =&gt; 3,\r\n        };\r\n        St((self.0 + 1) | (c &lt;&lt; (4 + 5 * self.len())))\r\n    }\r\n}\r\n<\/pre>\n<p>This code simply doesn&#8217;t compile because it only covers four of the possible 27 cases (A-Z + None). Of course, this only works for certain kinds of matches (typically, those involving enums); less help is available for instance in the inverse of the above operation:<\/p>\n<pre class=\"brush: rust; title: ; notranslate\" title=\"\">\r\nimpl Index&lt;u8&gt; for St {\r\n    type Output = Ch;\r\n\r\n    fn index(&amp;self, index: u8) -&gt; &amp;Self::Output {\r\n        let c = (self.0 &gt;&gt; (4 + 5 * index)) &amp; 0x1F;\r\n        match c {\r\n            1 =&gt; &amp;Ch::A,\r\n            2 =&gt; &amp;Ch::B,\r\n            3 =&gt; &amp;Ch::C,\r\n            _ =&gt; &amp;Ch::None,\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>This code would not compile without the <a href=\"https:\/\/doc.rust-lang.org\/book\/ch06-02-match.html#the-_-placeholder\">_ placeholder<\/a>, unless we specifically listed out every possible numeric value. This is in theory achievable for a <code>u8<\/code> type (&#8220;only&#8221; 256 values) but would be out of the question for any larger data type. The <a href=\"https:\/\/blog.logrocket.com\/using-the-rust-compiler-as-your-integration-testing-framework\/\">compiler is great at reducing the kinds of tests we need<\/a>, but alas we can&#8217;t throw them all away.<\/p>\n<p>We have a good start yet there is a lot more work to do. Let&#8217;s continue our Rust journey in the next post.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We&#8217;ve already set up the development environment, so let&#8217;s write some Rust code! A good place to start is with the bottom layer data structures, known as Str and Ch in the C# version. To review, Ch is an enumeration&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[91,101,41],"tags":[],"class_list":["post-5812","post","type-post","status-publish","format-standard","hentry","category-design","category-native","category-tdd"],"_links":{"self":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5812","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5812"}],"version-history":[{"count":9,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5812\/revisions"}],"predecessor-version":[{"id":5821,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5812\/revisions\/5821"}],"wp:attachment":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5812"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5812"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5812"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}