sass_alt/
SassFunctionList.rs

1// This file is part of sass-alt. It is subject to the license terms in the COPYRIGHT file found in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/sass-alt/master/COPYRIGHT. No part of predicator, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the COPYRIGHT file.
2// Copyright © 2017 The developers of sass-alt. See the COPYRIGHT file in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/sass-alt/master/COPYRIGHT.
3
4
5/// A wrapper type that holds a list of SASS functions and their Rust representations so that Rust function lifetimes exceed references to SASS functions held by the libsass C object Sass_Function_List.
6#[derive(Debug)]
7pub struct SassFunctionList(Sass_Function_List, Vec<Box<SassFunctionTraitObject>>);
8
9impl Drop for SassFunctionList
10{
11	#[inline(always)]
12	fn drop(&mut self)
13	{
14		self.0.delete()
15	}
16}
17
18impl Default for SassFunctionList
19{
20	#[inline(always)]
21	fn default() -> Self
22	{
23		Self::new(vec![])
24	}
25}
26
27impl SassFunctionList
28{
29	/// Create a new list of SASS functions. Called by value as we need to take ownership of the SASS functions to manage their lifetimes.
30	#[inline(always)]
31	pub fn new(sass_functions: Vec<SassFunctionTraitObject>) -> Self
32	{
33		let list = Sass_Function_List::make(sass_functions.len());
34		let mut drop_sass_functions_when_function_list_drops = Vec::with_capacity(sass_functions.len());
35		let mut index = 0;
36		for sass_function in sass_functions
37		{
38			let signature = CString::new(sass_function.signature().as_str()).unwrap();
39			
40			let mut cookie_holder: Box<SassFunctionTraitObject> = Box::new(sass_function);
41			let cookie = cookie_holder.as_mut() as *mut _ as *mut ::std::os::raw::c_void;
42			
43			let function_entry = unsafe { sass_make_function(signature.as_ptr(), Some(Self::call), cookie) };
44			
45			drop_sass_functions_when_function_list_drops.push(cookie_holder);
46			list.set_list_entry(index, function_entry);
47			index += 1;
48		}
49		SassFunctionList(list, drop_sass_functions_when_function_list_drops)
50	}
51	
52	extern "C" fn call(s_args: *const Sass_Value, cb: Sass_Function_Entry, comp: *mut Sass_Compiler) -> *mut Sass_Value
53	{
54		let cookie = cb.get_cookie();
55		let raw_this = cookie as *mut SassFunctionTraitObject;
56		let this = unsafe { &mut *raw_this };
57		let arguments = SassValue(s_args as *mut _, false);
58		
59		let result = if let Ok(arguments_list) = arguments.as_list()
60		{
61			match this.callback(arguments_list, SassCompiler(comp))
62			{
63				Ok(result) => result,
64				Err(error) => if let Ok(c_string) = CString::new(error.description())
65				{
66					SassValue::new_error(&c_string)
67				}
68				else
69				{
70					SassValue::new_error(&CString::new("error from custom SASS function was invalid").unwrap())
71				},
72			}
73		}
74		else
75		{
76			SassValue::new_error(&CString::new("arguments supplied were not a list; is this a bug in libsass?").unwrap())
77		};
78		result.transfer_ownership_to_c()
79	}
80	
81	#[inline(always)]
82	fn set_functions_on_options(&self, options: *mut Sass_Options)
83	{
84		if !self.1.is_empty()
85		{
86			options.set_c_functions(self.0);
87		}
88	}
89}