Repository: tarkah/tickrs (language: rust)

Issue:
Hard crash when scrolling through the options list (index out of bounds)
I just hit a hard crash when scrolling through the options list (just using the down arrow to go through the list of dates).

Here is the backtrace - hope it helps. Let me know if you need more information.

```
$ env RUST_BACKTRACE=full tickrs
Backtrace (most recent call first):
  File "<unknown>", line 0, in <tickrs::widget::options::OptionsWidget as tui::widgets::StatefulWidget>::render
  File "<unknown>", line 0, in tickrs::draw::draw_main
  File "<unknown>", line 0, in tui::terminal::Terminal<B>::draw
  File "<unknown>", line 0, in tickrs::main
  File "<unknown>", line 0, in std::rt::lang_start::{{closure}}
  File "rust:src/libstd/rt.rs", line 52, in std::rt::lang_start_internal::{{closure}}
  File "rust:src/libstd/panicking.rs", line 297, in std::panicking::try::do_call
  File "rust:src/libstd/panicking.rs", line 274, in std::panicking::try
  File "rust:src/libstd/panic.rs", line 394, in std::panic::catch_unwind
  File "rust:src/libstd/rt.rs", line 51, in std::rt::lang_start_internal
  File "<unknown>", line 0, in main
  File "<unknown>", line 0, in __libc_start_main
  File "<unknown>", line 0, in _start

The application panicked (crashed).
  index out of bounds: the len is 0 but the index is 0
in src/widget/options.rs, line 386
thread: main

```


Discussion / hints:
Thanks! Yeah the backtrace tells me exactly where the problem is. Out of curiosity, what symbol did it crash on?
oo, good question! 🙈 Can't remember, but it was one of the tech stonks because I was watching the show today 🍿😎 amazon, tesla, apple, amd, nvidia - one of those

On September 8, 2020 8:13:10 PM UTC, Cory Forsstrom <notifications@github.com> wrote:
>Thanks! Yeah the backtrace tells me exactly where the problem is. Out
>of curiosity, what symbol did it crash on?


Fix patch:
diff --git a/src/widget/options.rs b/src/widget/options.rs
index 80bd683..881d135 100644
--- a/src/widget/options.rs
+++ b/src/widget/options.rs
@@ -383,76 +383,77 @@ impl StatefulWidget for OptionsWidget {
                     &state.data.as_ref().unwrap().puts[..]
                 };
 
-                let option = &option_range[idx];
-
-                let mut columns = Layout::default()
-                    .direction(Direction::Horizontal)
-                    .constraints([Constraint::Length(20), Constraint::Length(20)].as_ref())
-                    .split(chunks[1]);
-
-                columns[1] = add_padding(columns[1], 2, PaddingDirection::Left);
-
-                let currency = option.currency.as_deref().unwrap_or("USD");
-
-                let gap_strike = 19 - (format!("{:.2} {}", option.strike, currency).len() + 7);
-                let gap_last = 15 - (format!("{:.2}", option.last_price).len() + 6);
-                let gap_ask = 15 - (format!("{:.2}", option.ask.unwrap_or_default()).len() + 4);
-                let gap_bid = 15 - (format!("{:.2}", option.bid.unwrap_or_default()).len() + 4);
-                let gap_volume = 18 - (format!("{}", option.volume.unwrap_or_default()).len() + 7);
-                let gap_open_int =
-                    18 - (format!("{}", option.open_interest.unwrap_or_default()).len() + 9);
-                let gap_impl_vol = 18
-                    - (format!(
-                        "{:.0}%",
-                        option.implied_volatility.unwrap_or_default() * 100.0
-                    )
-                    .len()
-                        + 11);
-
-                let column_0 = [
-                    Text::raw(format!(
-                        "strike:{}{:.2} {}\n\n",
-                        " ".repeat(gap_strike),
-                        option.strike,
-                        currency
-                    )),
-                    Text::raw(format!(
-                        "price:{}{:.2}\n\n",
-                        " ".repeat(gap_last),
-                        option.last_price,
-                    )),
-                    Text::raw(format!(
-                        "bid:{}{:.2}\n\n",
-                        " ".repeat(gap_ask),
-                        option.bid.unwrap_or_default(),
-                    )),
-                    Text::raw(format!(
-                        "ask:{}{:.2}",
-                        " ".repeat(gap_bid),
-                        option.ask.unwrap_or_default(),
-                    )),
-                ];
-
-                let column_1 = [
-                    Text::raw(format!(
-                        "volume:{}{}\n\n",
-                        " ".repeat(gap_volume),
-                        option.volume.unwrap_or_default(),
-                    )),
-                    Text::raw(format!(
-                        "interest:{}{}\n\n",
-                        " ".repeat(gap_open_int),
-                        option.open_interest.unwrap_or_default()
-                    )),
-                    Text::raw(format!(
-                        "volatility:{}{:.0}%",
-                        " ".repeat(gap_impl_vol),
-                        option.implied_volatility.unwrap_or_default() * 100.0
-                    )),
-                ];
-
-                Paragraph::new(column_0.iter()).render(columns[0], buf);
-                Paragraph::new(column_1.iter()).render(columns[1], buf);
+                if let Some(option) = option_range.get(idx) {
+                    let mut columns = Layout::default()
+                        .direction(Direction::Horizontal)
+                        .constraints([Constraint::Length(20), Constraint::Length(20)].as_ref())
+                        .split(chunks[1]);
+
+                    columns[1] = add_padding(columns[1], 2, PaddingDirection::Left);
+
+                    let currency = option.currency.as_deref().unwrap_or("USD");
+
+                    let gap_strike = 19 - (format!("{:.2} {}", option.strike, currency).len() + 7);
+                    let gap_last = 15 - (format!("{:.2}", option.last_price).len() + 6);
+                    let gap_ask = 15 - (format!("{:.2}", option.ask.unwrap_or_default()).len() + 4);
+                    let gap_bid = 15 - (format!("{:.2}", option.bid.unwrap_or_default()).len() + 4);
+                    let gap_volume =
+                        18 - (format!("{}", option.volume.unwrap_or_default()).len() + 7);
+                    let gap_open_int =
+                        18 - (format!("{}", option.open_interest.unwrap_or_default()).len() + 9);
+                    let gap_impl_vol = 18
+                        - (format!(
+                            "{:.0}%",
+                            option.implied_volatility.unwrap_or_default() * 100.0
+                        )
+                        .len()
+                            + 11);
+
+                    let column_0 = [
+                        Text::raw(format!(
+                            "strike:{}{:.2} {}\n\n",
+                            " ".repeat(gap_strike),
+                            option.strike,
+                            currency
+                        )),
+                        Text::raw(format!(
+                            "price:{}{:.2}\n\n",
+                            " ".repeat(gap_last),
+                            option.last_price,
+                        )),
+                        Text::raw(format!(
+                            "bid:{}{:.2}\n\n",
+                            " ".repeat(gap_ask),
+                            option.bid.unwrap_or_default(),
+                        )),
+                        Text::raw(format!(
+                            "ask:{}{:.2}",
+                            " ".repeat(gap_bid),
+                            option.ask.unwrap_or_default(),
+                        )),
+                    ];
+
+                    let column_1 = [
+                        Text::raw(format!(
+                            "volume:{}{}\n\n",
+                            " ".repeat(gap_volume),
+                            option.volume.unwrap_or_default(),
+                        )),
+                        Text::raw(format!(
+                            "interest:{}{}\n\n",
+                            " ".repeat(gap_open_int),
+                            option.open_interest.unwrap_or_default()
+                        )),
+                        Text::raw(format!(
+                            "volatility:{}{:.0}%",
+                            " ".repeat(gap_impl_vol),
+                            option.implied_volatility.unwrap_or_default() * 100.0
+                        )),
+                    ];
+
+                    Paragraph::new(column_0.iter()).render(columns[0], buf);
+                    Paragraph::new(column_1.iter()).render(columns[1], buf);
+                }
             }
         }
     }


Test patch: