You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: time_range_udf.rs
    path of file: ./repos/openobserve/src/service/search/datafusion
    
    the code of the file until where you have to start completion: // Copyright 2023 Zinc Labs Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::{iter::zip, sync::Arc};

use config::utils::{str, time};
use datafusion::{
    arrow::{
        array::{ArrayRef, BooleanArray, Int64Array,
    
pub fn time_range_expr_impl() -> ScalarFunctionImplementation {
    let func = move |args: &[ArrayRef]| -> datafusion::error::Result<ArrayRef> {
        if args.len() != 3 {
            return Err(DataFusionError::SQL(
                ParserError::ParserError(
                    "UDF params should be: time_range(field, start, end)".to_string(),
                ),
                None,
            ));
        }

        // 1. cast both arguments to Union. These casts MUST be aligned with the signature or this
        //    function panics!
        let base = &args[0]
            .as_any()
            .downcast_ref::<Int64Array>()
            .expect("cast failed");
        let min = &args[1]
            .as_any()
            .downcast_ref::<StringArray>()
            .expect("cast failed");
        let max = &args[2]
            .as_any()
            .downcast_ref::<StringArray>()
            .expect("cast failed");

        // 2. perform the computation
        let array = zip(base.iter(), zip(min.iter(), max.iter()))
            .map(|(base, val)| {
                match (base, val) {
                    // in arrow, any value can be null.
                    // Here we decide to make our UDF to return null when either argument is null.
                    (Some(base), (Some(min), Some(max))) => {
                        let min = match time::parse_str_to_timestamp_micros(min) {
                            Ok(v) => v,
                            Err(_) => return None,
                        };
                        let max = match time::parse_str_to_timestamp_micros(max) {
                            Ok(v) => v,
                            Err(_) => return None,
                        };
                        let result: bool;
                        if min > 0 && max > 0 {
                            result = base >= min && base < max;
                        } else if min > 0 {
                            result = base >= min;
                        } else if max > 0 {
                            result = base < max;
                        } else {
                            result = true;
                        }
                        Some(result)
                    }
                    _ => None,
                }
            })
            .collect::<BooleanArray>();

        // `Ok` because no error occurred during the calculation
        // `Arc` because arrays are immutable, thread-safe, trait objects.
        Ok(Arc::new(array) as ArrayRef)
    };

    make_scalar_function(func)
}