{"id":5822,"date":"2021-04-02T07:00:30","date_gmt":"2021-04-02T14:00:30","guid":{"rendered":"http:\/\/writeasync.net\/?p=5822"},"modified":"2021-03-31T10:34:48","modified_gmt":"2021-03-31T17:34:48","slug":"letter-boxed-rust-impl-part-2-panicking-hashing-parsing","status":"publish","type":"post","link":"https:\/\/writeasync.net\/?p=5822","title":{"rendered":"Letter Boxed: Rust impl, part 2 (panicking, hashing, parsing)"},"content":{"rendered":"<p>Previously we began our <a href=\"http:\/\/writeasync.net\/?p=5812\">Rust exploration of Letter Boxed<\/a> with the core <code>St<\/code> and <code>Ch<\/code> structs. Now we&#8217;ll complete their functionality.<\/p>\n<p>The next test on our TODO list looks like this <a href=\"https:\/\/github.com\/brian-dot-net\/games\/blob\/adb9f0b6efee0b8b26d2623fbfb7ee11db08ff9f\/test\/Words.Test\/StrTest.cs#L190\">in the C# version<\/a>:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n        &#x5B;Fact]\r\n        public void AppendTooMany()\r\n        {\r\n            Str max = default(Str)\r\n                .Append(Ch.A)\r\n                .Append(Ch.B)\r\n                .Append(Ch.C)\r\n                .Append(Ch.D)\r\n                .Append(Ch.E)\r\n                .Append(Ch.F)\r\n                .Append(Ch.G)\r\n                .Append(Ch.H)\r\n                .Append(Ch.I)\r\n                .Append(Ch.J)\r\n                .Append(Ch.K)\r\n                .Append(Ch.L);\r\n\r\n            Action act = () =&gt; max.Append(Ch.X);\r\n\r\n            act.Should().Throw&lt;InvalidOperationException&gt;();\r\n        }\r\n<\/pre>\n<p>We&#8217;ve already encountered our first roadblock &#8212; <a href=\"https:\/\/blog.knoldus.com\/you-can-live-without-exceptions-if-you-are-using-rust\/\">Rust does not have exceptions<\/a>. Instead, you either <a href=\"https:\/\/doc.rust-lang.org\/book\/ch09-02-recoverable-errors-with-result.html\">use an error result<\/a> for things that could reasonably happen in a typical flow (e.g. when parsing external data) or <a href=\"https:\/\/www.ralfj.de\/blog\/2019\/11\/25\/how-to-panic-in-rust.html\">you panic<\/a>! We&#8217;ll choose the latter in this particular case; appending past the end of a buffer is an indication of an incorrect program and not something that we would want to compensate for or recover from.<\/p>\n<p>Here is the Rust version of this test, using the <a href=\"https:\/\/doc.rust-lang.org\/book\/ch11-01-writing-tests.html#checking-for-panics-with-should_panic\">[should_panic]<\/a> annotation:<\/p>\n<pre class=\"brush: rust; title: ; notranslate\" title=\"\">\r\n    #&#x5B;test]\r\n    #&#x5B;should_panic(expected = &quot;Cannot append any more&quot;)]\r\n    fn append_too_many() {\r\n        let max = St::empty()\r\n            + Ch::A\r\n            + Ch::B\r\n            + Ch::C\r\n            + Ch::D\r\n            + Ch::E\r\n            + Ch::F\r\n            + Ch::G\r\n            + Ch::H\r\n            + Ch::I\r\n            + Ch::J\r\n            + Ch::K\r\n            + Ch::L;\r\n\r\n        let _ = max + Ch::X;\r\n    }\r\n<\/pre>\n<p>Note the use of <a href=\"https:\/\/stackoverflow.com\/questions\/48361537\/why-do-underscore-prefixed-variables-exist\">the underscore variable<\/a> since we expect this line to panic and cannot do anything with the value. To pass this test, we only need a small tweak to the <code>add<\/code> function:<\/p>\n<pre class=\"brush: rust; title: ; notranslate\" title=\"\">\r\n    fn add(self, rhs: Ch) -&gt; Self::Output {\r\n        if self.len() == 12 {\r\n            panic!(&quot;Cannot append any more&quot;);\r\n        }\r\n        \/\/ . . .\r\n    }\r\n<\/pre>\n<p>Not bad! We can follow this same pattern for the <a href=\"https:\/\/github.com\/brian-dot-net\/games\/commit\/52d1e6bea04e9c448d585d655098929a0bdf39fd\">index out of range condition<\/a> and the <a href=\"https:\/\/github.com\/brian-dot-net\/games\/commit\/9ae9126d043f3b15a01a188c6edd3e48fb1d1dad\">new <code>chop<\/code> function<\/a> which drops the last <code>Ch<\/code> from the <code>St<\/code>.<\/p>\n<p>The end goal with <code>St<\/code> is to support a fast lookup strategy, so naturally we should reach for <a href=\"https:\/\/doc.rust-lang.org\/std\/hash\/trait.Hash.html\">the Hash trait<\/a> next. It is <a href=\"https:\/\/stackoverflow.com\/questions\/53135923\/how-to-write-a-custom-derive-macro\">auto-derivable<\/a>, with the default implementation hashing all fields together. How convenient. There is  an important difference in how hashing works in Rust compared to .NET, however. Since Rust has <a href=\"https:\/\/stevedonovan.github.io\/rust-gentle-intro\/object-orientation.html\">no implementation inheritance<\/a> and <a href=\"https:\/\/www.stroustrup.com\/bs_faq2.html#object\">no universal base class<\/a>, we can&#8217;t just make a <a href=\"https:\/\/ericlippert.com\/2011\/02\/28\/guidelines-and-rules-for-gethashcode\/\">virtual GetHashCode method<\/a> and be done with it. Instead, &#8220;hashable&#8221; types are supposed to produce their hash code when <a href=\"https:\/\/doc.rust-lang.org\/std\/hash\/trait.Hasher.html\">given a &#8220;hasher&#8221;<\/a> which allows a bit more modularity between the what (i.e. data to consider) and the how (i.e. the algorithm) of hashing. You can see this difference by comparing the C# and Rust versions of the hash code test:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n        &#x5B;Fact]\r\n        public void HashCode()\r\n        {\r\n            Str empty = default(Str);\r\n            Str a = default(Str).Append(Ch.A);\r\n            Str b = default(Str).Append(Ch.B);\r\n            Str ab = default(Str).Append(Ch.A).Append(Ch.B);\r\n            Str ba = default(Str).Append(Ch.B).Append(Ch.A);\r\n            Str cdefgh = default(Str).Append(Ch.C).Append(Ch.D).Append(Ch.E).Append(Ch.F).Append(Ch.G).Append(Ch.H);\r\n\r\n            HashSet&lt;int&gt; codes = new HashSet&lt;int&gt;(new Str&#x5B;] { empty, a, b, ab, ba, cdefgh }.Select(s =&gt; s.GetHashCode()));\r\n\r\n            codes.Should().HaveCount(6);\r\n        }\r\n<\/pre>\n<p>In Rust, we have the extra step of working with a <a href=\"https:\/\/stackoverflow.com\/questions\/28587698\/whats-the-difference-between-placing-mut-before-a-variable-name-and-after-the\">mutable<\/a> hasher:<\/p>\n<pre class=\"brush: rust; title: ; notranslate\" title=\"\">\r\n    #&#x5B;test]\r\n    fn hash_code() {\r\n        let empty = St::empty();\r\n        let a = St::empty() + Ch::A;\r\n        let b = St::empty() + Ch::B;\r\n        let ab = St::empty() + Ch::A + Ch::B;\r\n        let ba = St::empty() + Ch::B + Ch::A;\r\n        let cdefgh = St::empty() + Ch::C + Ch::D + Ch::E + Ch::F + Ch::G + Ch::H;\r\n        let values = vec!&#x5B;empty, a, b, ab, ba, cdefgh];\r\n\r\n        let codes: HashSet&lt;u64&gt; = values\r\n            .into_iter()\r\n            .map(|s| {\r\n                let mut hasher = DefaultHasher::new();\r\n                s.hash(&amp;mut hasher);\r\n                hasher.finish()\r\n            })\r\n            .collect();\r\n        assert_eq!(6, codes.len());\r\n    }\r\n<\/pre>\n<p>It&#8217;s a slight difference but not all that impactful outside the unit testing context. In a typical program, we are unlikely to directly ask for the hash code (we&#8217;d probably just put the item in a <a href=\"https:\/\/doc.rust-lang.org\/rust-by-example\/std\/hash.html\">HashMap<\/a> and let the collection do the heavy lifting).<\/p>\n<p>The last requirement is the ability to convert a string like &#8220;HELLO&#8221; into a <code>St<\/code> with values <code>Ch::H<\/code>, <code>Ch::E<\/code>, <code>Ch::L<\/code>, <code>Ch::L<\/code>, <code>Ch::O<\/code> inside. As you may have guessed, there&#8217;s a trait for that &#8212; <a href=\"https:\/\/doc.rust-lang.org\/nightly\/core\/str\/trait.FromStr.html\">FromStr<\/a>. Unlike some other traits, the <code>from_str<\/code> method here is not typically used directly. Rather, you call <a href=\"https:\/\/doc.rust-lang.org\/std\/primitive.str.html#method.parse\"><code>str::parse<\/code><\/a> which in turn calls <code>from_str<\/code>. As the docs say, you will more than likely have to use the <a href=\"https:\/\/techblog.tonsser.com\/posts\/what-is-rusts-turbofish\">&#8220;turbofish syntax&#8221;<\/a> to ensure Rust understands what the output type should be in context. Here is the unit test showing this in action:<\/p>\n<pre class=\"brush: rust; title: ; notranslate\" title=\"\">\r\n    #&#x5B;test]\r\n    fn parse_from_string() {\r\n        test_parse(&quot;&quot;);\r\n        test_parse(&quot;A&quot;);\r\n        test_parse(&quot;BC&quot;);\r\n        \/\/ . . .\r\n    }\r\n\r\n    fn test_parse(expected: &amp;str) {\r\n        let s = expected.parse::&lt;St&gt;().unwrap();\r\n        assert_eq!(expected, s.to_string());\r\n    }\r\n<\/pre>\n<p>As a final note, you should be aware that Rust considers string parsing to be a <a href=\"https:\/\/stevedonovan.github.io\/rustifications\/2018\/09\/08\/common-rust-traits.html#fallible-conversions---fromstr\">fallible conversion<\/a>. As such, the return value is a <a href=\"https:\/\/learning-rust.github.io\/docs\/e3.option_and_result.html\">Result type<\/a> that can have either a value or an error. In this case, we don&#8217;t want to bother with returning an error and will just assume that converting to <code>St<\/code> will either succeed or panic. While we cannot change the function signature, we can indicate there is no such thing as an error here by using the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Unit_type\">unit type<\/a> (essentially <a href=\"https:\/\/en.wikipedia.org\/wiki\/Void_type\">&#8220;void&#8221;<\/a>):<\/p>\n<pre class=\"brush: rust; title: ; notranslate\" title=\"\">\r\nimpl FromStr for St {\r\n    type Err = ();\r\n\r\n    fn from_str(s: &amp;str) -&gt; Result&lt;St, ()&gt; {\r\n        let mut value = St::empty();\r\n        for c in s.chars() {\r\n            let c = match c {\r\n                'A' =&gt; Ch::A,\r\n                \/\/ . . .\r\n                'Z' =&gt; Ch::Z,\r\n                _ =&gt; Ch::None,\r\n            };\r\n            value = value + c;\r\n        }\r\n\r\n        Ok(value)\r\n    }\r\n}\r\n<\/pre>\n<p>The <code>type Err = ();<\/code> line says that our error type is nothing at all, and as a consequence, our function returns <code>Ok<\/code> in all (non-panic) paths.<\/p>\n<p>With that, our base data structure logic is done: <a href=\"https:\/\/github.com\/brian-dot-net\/games\/blob\/51426b234972f796736df7369e49c4f2c2aa0303\/letter_boxed_solver\/src\/lib.rs\">[see code on GitHub]<\/a><\/p>\n<p>Going forward, we&#8217;ll get into the nuts and bolts of the higher level algorithms and structures of Letter Boxed. See you again soon!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Previously we began our Rust exploration of Letter Boxed with the core St and Ch structs. Now we&#8217;ll complete their functionality. The next test on our TODO list looks like this in the C# version: &#x5B;Fact] public void AppendTooMany() {&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-5822","post","type-post","status-publish","format-standard","hentry","category-design","category-native","category-tdd"],"_links":{"self":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5822","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5822"}],"version-history":[{"count":5,"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5822\/revisions"}],"predecessor-version":[{"id":5827,"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5822\/revisions\/5827"}],"wp:attachment":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5822"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5822"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5822"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}