pub(crate) fn evaluate<S: AsRef<str>>(
        &mut self,
        code: S,
        args: S,
        limit: time::Duration,
    ) -> io::Result<String> {
        // @FIXME note the comment below:
        // my assumption is that it's still secure to reuse contexts given an empty stack
        // secure as in an execution can't reference any data in the heap from a
        // previous execution, given there are no globals and no stack frames
        // if this is not the case, we'd want to initialize a new heap on each call, but
        // this has overheads.

        if !args.as_ref().trim_start().starts_with('[') {
            // a simple validation hack, given that we require args to be an array, not
            // simply any parseable JSON value
            return Err(io::Error::new(
                io::ErrorKind::Other,
                "args must be a JSON-encoded array",
            ));
        }

        let code = CString::new(code.as_ref())?;
        let code_ptr = code.as_ptr();

        let args = CString::new(args.as_ref())?;
        let args_ptr = args.as_ptr();

        let function = CString::new("function")?;
        let function_ptr = function.as_ptr();

        let loader =
            CString::new("function(fn, args) { return fn.apply(null, JSON.parse(args)); }")?;
        let loader_ptr = loader.as_ptr();

        // Clear the existing stack and setup a new evaluation context (timestamp)
        self.duk_clear_stack();

        unsafe {
            (*self.latest_evaluate_context).clear();
            (*self.latest_evaluate_context).push(EvaluateContext {
                start: time::Instant::now(),
                limit,
            });
        }

        // Load our functions onto the stack
        {
            unsafe {
                duktape::duk_push_string(self.ctx, loader_ptr);
                duktape::duk_push_string(self.ctx, function_ptr);
            }

            self.duk_compile().map_err(|e| {
                self.duk_clear_stack();
                e
            })?;
        }

        {
            unsafe {
                duktape::duk_push_string(self.ctx, code_ptr);
                duktape::duk_push_string(self.ctx, function_ptr);
            }

            self.duk_compile().map_err(|e| {
                self.duk_clear_stack();
                e
            })?;
        }

        // Execute
        let result = unsafe {
            duktape::duk_push_string(self.ctx, args_ptr);

            duktape::duk_pcall(self.ctx, 2) // 2 arguments
        };

        if result == 0 {
            // we've successfully executed, thus the stack is non-empty. Attempt to
            // encode it as JSON, and if successful, copy it to an owned String

            let json_ptr = unsafe { duktape::duk_json_encode(self.ctx, 0) };

            if json_ptr.is_null() {
                self.duk_clear_stack();

                Err(io::Error::new(io::ErrorKind::Other, "undefined"))
            } else {
                let json_cstr = unsafe { CStr::from_ptr(json_ptr) };

                let json_string: String = json_cstr
                    .to_str()
                    .map_err(|_e| io::Error::new(io::ErrorKind::Other, "undefined"))?
                    .to_string();

                self.duk_clear_stack();

                Ok(json_string)
            }
        } else {
            let error_result = self
                .duk_error_message()
                .and_then(|e| Err(io::Error::new(io::ErrorKind::Other, e)));

            self.duk_clear_stack();

            error_result
        }
    }
/// Evaluates a JavaScript function given its definition and a JSON-encoded array of
/// arguments for the function.
Evaluates a JavaScript function given its definition and a JSON-encoded array of
arguments for the function.
Evaluates a JavaScript function given its definition and a JSON - encoded array of arguments for the function .
pub(crate) fn evaluate<S: AsRef<str>>(
        &mut self,
        code: S,
        args: S,
        limit: time::Duration,
    ) -> io::Result<String> {
        // @FIXME note the comment below:
        // my assumption is that it's still secure to reuse contexts given an empty stack
        // secure as in an execution can't reference any data in the heap from a
        // previous execution, given there are no globals and no stack frames
        // if this is not the case, we'd want to initialize a new heap on each call, but
        // this has overheads.
        if !args.as_ref().trim_start().starts_with('[') {
            // a simple validation hack, given that we require args to be an array, not
            // simply any parseable JSON value
            return Err(io::Error::new(
                io::ErrorKind::Other,
                "args must be a JSON-encoded array",
            ));
        }
        let code = CString::new(code.as_ref())?;
        let code_ptr = code.as_ptr();
        let args = CString::new(args.as_ref())?;
        let args_ptr = args.as_ptr();
        let function = CString::new("function")?;
        let function_ptr = function.as_ptr();
        let loader =
            CString::new("function(fn, args) { return fn.apply(null, JSON.parse(args)); }")?;
        let loader_ptr = loader.as_ptr();
        // Clear the existing stack and setup a new evaluation context (timestamp)
        self.duk_clear_stack();
        unsafe {
            (*self.latest_evaluate_context).clear();
            (*self.latest_evaluate_context).push(EvaluateContext {
                start: time::Instant::now(),
                limit,
            });
        }
        // Load our functions onto the stack
        {
            unsafe {
                duktape::duk_push_string(self.ctx, loader_ptr);
                duktape::duk_push_string(self.ctx, function_ptr);
            }
            self.duk_compile().map_err(|e| {
                self.duk_clear_stack();
                e
            })?;
        }
        {
            unsafe {
                duktape::duk_push_string(self.ctx, code_ptr);
                duktape::duk_push_string(self.ctx, function_ptr);
            }
            self.duk_compile().map_err(|e| {
                self.duk_clear_stack();
                e
            })?;
        }
        // Execute
        let result = unsafe {
            duktape::duk_push_string(self.ctx, args_ptr);
            duktape::duk_pcall(self.ctx, 2) // 2 arguments
        };
        if result == 0 {
            // we've successfully executed, thus the stack is non-empty. Attempt to
            // encode it as JSON, and if successful, copy it to an owned String
            let json_ptr = unsafe { duktape::duk_json_encode(self.ctx, 0) };
            if json_ptr.is_null() {
                self.duk_clear_stack();
                Err(io::Error::new(io::ErrorKind::Other, "undefined"))
            } else {
                let json_cstr = unsafe { CStr::from_ptr(json_ptr) };
                let json_string: String = json_cstr
                    .to_str()
                    .map_err(|_e| io::Error::new(io::ErrorKind::Other, "undefined"))?
                    .to_string();
                self.duk_clear_stack();
                Ok(json_string)
            }
        } else {
            let error_result = self
                .duk_error_message()
                .and_then(|e| Err(io::Error::new(io::ErrorKind::Other, e)));
            self.duk_clear_stack();
            error_result
        }
    }
pub ( crate ) fn evaluate < S : AsRef < str > > ( & mut self , code : S , args : S , limit : time :: Duration , ) -> io :: Result < String > { // @FIXME note the comment below: // my assumption is that it's still secure to reuse contexts given an empty stack // secure as in an execution can't reference any data in the heap from a // previous execution, given there are no globals and no stack frames // if this is not the case, we'd want to initialize a new heap on each call, but // this has overheads. if ! args . as_ref ( ) . trim_start ( ) . starts_with ( '[' ) { // a simple validation hack, given that we require args to be an array, not // simply any parseable JSON value return Err ( io :: Error :: new ( io :: ErrorKind :: Other , " " , ) ) ; } let code = CString :: new ( code . as_ref ( ) ) ? ; let code_ptr = code . as_ptr ( ) ; let args = CString :: new ( args . as_ref ( ) ) ? ; let args_ptr = args . as_ptr ( ) ; let function = CString :: new ( " " ) ? ; let function_ptr = function . as_ptr ( ) ; let loader = CString :: new ( " " ) ? ; let loader_ptr = loader . as_ptr ( ) ; // Clear the existing stack and setup a new evaluation context (timestamp) self . duk_clear_stack ( ) ; unsafe { ( * self . latest_evaluate_context ) . clear ( ) ; ( * self . latest_evaluate_context ) . push ( EvaluateContext { start : time :: Instant :: now ( ) , limit , } ) ; } // Load our functions onto the stack { unsafe { duktape :: duk_push_string ( self . ctx , loader_ptr ) ; duktape :: duk_push_string ( self . ctx , function_ptr ) ; } self . duk_compile ( ) . map_err ( | e | { self . duk_clear_stack ( ) ; e } ) ? ; } { unsafe { duktape :: duk_push_string ( self . ctx , code_ptr ) ; duktape :: duk_push_string ( self . ctx , function_ptr ) ; } self . duk_compile ( ) . map_err ( | e | { self . duk_clear_stack ( ) ; e } ) ? ; } // Execute let result = unsafe { duktape :: duk_push_string ( self . ctx , args_ptr ) ; duktape :: duk_pcall ( self . ctx , 2 ) // 2 arguments } ; if result == 0 { // we've successfully executed, thus the stack is non-empty. Attempt to // encode it as JSON, and if successful, copy it to an owned String let json_ptr = unsafe { duktape :: duk_json_encode ( self . ctx , 0 ) } ; if json_ptr . is_null ( ) { self . duk_clear_stack ( ) ; Err ( io :: Error :: new ( io :: ErrorKind :: Other , " " ) ) } else { let json_cstr = unsafe { CStr :: from_ptr ( json_ptr ) } ; let json_string : String = json_cstr . to_str ( ) . map_err ( | _e | io :: Error :: new ( io :: ErrorKind :: Other , " " ) ) ? . to_string ( ) ; self . duk_clear_stack ( ) ; Ok ( json_string ) } } else { let error_result = self . duk_error_message ( ) . and_then ( | e | Err ( io :: Error :: new ( io :: ErrorKind :: Other , e ) ) ) ; self . duk_clear_stack ( ) ; error_result } }
Evaluates a JavaScript function given its definition and a JSON-encoded array of
arguments for the function.
Evaluates a JavaScript function given its definition and a JSON - encoded array of arguments for the function .
&mut self
code
S
args
S
limit
time::Duration