optimize: avoid using #[serde] in ops

This commit is contained in:
2026-02-18 20:57:21 +08:00
parent 42031edac1
commit b424f60f9f
7 changed files with 194 additions and 173 deletions

View File

@@ -377,16 +377,16 @@ export const derivationStrict = (args: NixValue): NixAttrs => {
const rustResult: {
drvPath: string;
outputs: [string, string][];
} = Deno.core.ops.op_finalize_derivation({
name: drvName,
} = Deno.core.ops.op_finalize_derivation(
drvName,
builder,
platform,
outputs,
args: drvArgs,
env: envEntries,
context: contextArray,
fixedOutput: fixedOutputInfo,
});
drvArgs,
envEntries,
contextArray,
fixedOutputInfo,
);
const result: NixAttrs = new Map();

View File

@@ -30,9 +30,5 @@ export const convertHash = (args: NixValue): string => {
const toHashFormat = forceStringNoCtx(select(attrs, ["toHashFormat"]));
return Deno.core.ops.op_convert_hash({
hash,
hashAlgo,
toHashFormat,
});
return Deno.core.ops.op_convert_hash(hash, hashAlgo, toHashFormat);
};

View File

@@ -49,8 +49,7 @@ export const importFunc = (path: NixValue): NixValue => {
return cached;
}
const code = Deno.core.ops.op_import(pathStr);
const result = Function(`return (${code})`)();
const result = Deno.core.ops.op_import(pathStr);
importCache.set(pathStr, result);
return result;
@@ -85,24 +84,24 @@ export const fetchClosure = (_args: NixValue): never => {
};
export interface FetchUrlResult {
store_path: string;
storePath: string;
hash: string;
}
export interface FetchTarballResult {
store_path: string;
nar_hash: string;
storePath: string;
narHash: string;
}
export interface FetchGitResult {
out_path: string;
outPath: string;
rev: string;
short_rev: string;
rev_count: number;
last_modified: number;
last_modified_date: string;
shortRev: string;
revCount: number;
lastModified: number;
lastModifiedDate: string;
submodules: boolean;
nar_hash: string | null;
narHash: string | null;
}
const normalizeUrlInput = (
@@ -154,16 +153,16 @@ export const fetchurl = (args: NixValue): NixString => {
executable ?? false,
);
const context: NixStringContext = new Set();
addOpaqueContext(context, result.store_path);
return mkStringWithContext(result.store_path, context);
addOpaqueContext(context, result.storePath);
return mkStringWithContext(result.storePath, context);
};
export const fetchTarball = (args: NixValue): NixString => {
const { url, name, sha256 } = normalizeTarballInput(args);
const result: FetchTarballResult = Deno.core.ops.op_fetch_tarball(url, name ?? null, sha256 ?? null);
const context: NixStringContext = new Set();
addOpaqueContext(context, result.store_path);
return mkStringWithContext(result.store_path, context);
addOpaqueContext(context, result.storePath);
return mkStringWithContext(result.storePath, context);
};
export const fetchGit = (args: NixValue): NixAttrs => {
@@ -173,16 +172,16 @@ export const fetchGit = (args: NixValue): NixAttrs => {
const url = coerceToString(forced, StringCoercionMode.Base, false, disposedContext);
const result = Deno.core.ops.op_fetch_git(url, null, null, false, false, false, null);
const outContext: NixStringContext = new Set();
addOpaqueContext(outContext, result.out_path);
addOpaqueContext(outContext, result.outPath);
return new Map<string, NixValue>([
["outPath", mkStringWithContext(result.out_path, outContext)],
["outPath", mkStringWithContext(result.outPath, outContext)],
["rev", result.rev],
["shortRev", result.short_rev],
["revCount", BigInt(result.rev_count)],
["lastModified", BigInt(result.last_modified)],
["lastModifiedDate", result.last_modified_date],
["shortRev", result.shortRev],
["revCount", BigInt(result.revCount)],
["lastModified", BigInt(result.lastModified)],
["lastModifiedDate", result.lastModifiedDate],
["submodules", result.submodules],
["narHash", result.nar_hash],
["narHash", result.narHash],
]);
}
const attrs = forceAttrs(args);
@@ -205,16 +204,16 @@ export const fetchGit = (args: NixValue): NixAttrs => {
);
const outContext: NixStringContext = new Set();
addOpaqueContext(outContext, result.out_path);
addOpaqueContext(outContext, result.outPath);
return new Map<string, NixValue>([
["outPath", mkStringWithContext(result.out_path, outContext)],
["outPath", mkStringWithContext(result.outPath, outContext)],
["rev", result.rev],
["shortRev", result.short_rev],
["revCount", BigInt(result.rev_count)],
["lastModified", BigInt(result.last_modified)],
["lastModifiedDate", result.last_modified_date],
["shortRev", result.shortRev],
["revCount", BigInt(result.revCount)],
["lastModified", BigInt(result.lastModified)],
["lastModifiedDate", result.lastModifiedDate],
["submodules", result.submodules],
["narHash", result.nar_hash],
["narHash", result.narHash],
]);
};
@@ -307,12 +306,7 @@ const autoDetectAndFetch = (attrs: NixAttrs): NixAttrs => {
export const readDir = (path: NixValue): NixAttrs => {
const pathStr = realisePath(path);
const entries: Record<string, string> = Deno.core.ops.op_read_dir(pathStr);
const result: NixAttrs = new Map();
for (const [name, type] of Object.entries(entries)) {
result.set(name, type);
}
return result;
return Deno.core.ops.op_read_dir(pathStr);
};
export const readFile = (path: NixValue): string => {

View File

@@ -305,7 +305,7 @@ export const assert = (assertion: NixValue, expr: NixValue, assertionRaw: string
};
export const mkPos = (span: number): NixAttrs => {
return new Map(Object.entries(Deno.core.ops.op_decode_span(span)));
return Deno.core.ops.op_decode_span(span);
};
interface WithScope {

View File

@@ -15,7 +15,7 @@ import type {
import type { op } from "../operators";
import type { createThunk, force } from "../thunk";
import type { forceBool } from "../type-assert";
import type { mkAttrs, mkFunction } from "../types";
import type { mkAttrs, mkFunction, NixAttrs } from "../types";
declare global {
var Nix: NixRuntime;
@@ -55,7 +55,7 @@ declare global {
function op_read_file(path: string): string;
function op_read_file_type(path: string): string;
function op_read_dir(path: string): Record<string, string>;
function op_read_dir(path: string): Map<string, string>;
function op_path_exists(path: string): boolean;
function op_walk_dir(path: string): [string, string][];
@@ -81,11 +81,7 @@ declare global {
includePaths: string[],
): string;
function op_decode_span(span: number): {
file: string | null;
line: number | null;
column: number | null;
};
function op_decode_span(span: number): NixAttrs;
function op_to_file(name: string, contents: string, references: string[]): string;
@@ -100,16 +96,16 @@ declare global {
function op_from_toml(toml: string): unknown;
function op_to_xml(e: NixValue): [string, string[]];
function op_finalize_derivation(input: {
name: string;
builder: string;
platform: string;
outputs: string[];
args: string[];
env: [string, string][];
context: string[];
fixedOutput: { hashAlgo: string; hash: string; hashMode: string } | null;
}): { drvPath: string; outputs: [string, string][] };
function op_finalize_derivation(
name: string,
builder: string,
platform: string,
outputs: string[],
args: string[],
env: [string, string][],
context: string[],
fixedOutput: { hashAlgo: string; hash: string; hashMode: string } | null,
): { drvPath: string; outputs: [string, string][] };
function op_fetch_url(
url: string,

View File

@@ -1,8 +1,8 @@
use deno_core::OpState;
use deno_core::ToV8;
use deno_core::op2;
use nix_compat::nixhash::HashAlgo;
use nix_compat::nixhash::NixHash;
use serde::Serialize;
use tracing::{debug, info, warn};
use crate::runtime::OpStateExt;
@@ -22,19 +22,19 @@ pub use metadata_cache::MetadataCache;
use crate::nar;
use crate::runtime::NixRuntimeError;
#[derive(Serialize)]
#[derive(ToV8)]
pub struct FetchUrlResult {
pub store_path: String,
pub hash: String,
}
#[derive(Serialize)]
#[derive(ToV8)]
pub struct FetchTarballResult {
pub store_path: String,
pub nar_hash: String,
}
#[derive(Serialize)]
#[derive(ToV8)]
pub struct FetchGitResult {
pub out_path: String,
pub rev: String,
@@ -47,7 +47,6 @@ pub struct FetchGitResult {
}
#[op2]
#[serde]
pub fn op_fetch_url<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] url: String,
@@ -152,7 +151,6 @@ pub fn op_fetch_url<Ctx: RuntimeContext>(
}
#[op2]
#[serde]
pub fn op_fetch_tarball<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] url: String,
@@ -266,7 +264,6 @@ pub fn op_fetch_tarball<Ctx: RuntimeContext>(
}
#[op2]
#[serde]
pub fn op_fetch_git<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] url: String,

View File

@@ -1,9 +1,11 @@
use std::collections::BTreeMap;
use std::convert::Infallible;
use std::path::{Component, Path, PathBuf};
use std::str::FromStr;
use hashbrown::hash_map::{Entry, HashMap};
use hashbrown::{HashMap, HashSet, hash_map::Entry};
use deno_core::{FromV8, OpState, v8};
use deno_core::{FromV8, OpState, ToV8, v8};
use regex::Regex;
use rust_embed::Embed;
@@ -36,6 +38,26 @@ impl RegexCache {
}
}
pub(super) struct Map<K, V>(HashMap<K, V>);
impl<'a, K, V> ToV8<'a> for Map<K, V>
where
K: ToV8<'a>,
K::Error: ToString,
V: ToV8<'a>,
V::Error: ToString,
{
type Error = NixRuntimeError;
fn to_v8<'i>(self, scope: &mut v8::PinScope<'a, 'i>) -> Result<v8::Local<'a, v8::Value>> {
let map = v8::Map::new(scope);
for (k, v) in self.0 {
let k = k.to_v8(scope).map_err(|err| err.to_string())?;
let v = v.to_v8(scope).map_err(|err| err.to_string())?;
map.set(scope, k, v).ok_or("Failed to set V8 Map KV")?;
}
Ok(map.into())
}
}
#[derive(Embed)]
#[folder = "src/runtime/corepkgs"]
pub(crate) struct CorePkgs;
@@ -93,7 +115,7 @@ pub(super) fn op_import<Ctx: RuntimeContext>(
pub(super) fn op_scoped_import<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] path: String,
#[serde] scope: Vec<String>,
#[scoped] scope: Vec<String>,
) -> Result<String> {
let _span = tracing::info_span!("op_scoped_import", path = %path).entered();
let ctx: &mut Ctx = state.get_ctx_mut();
@@ -161,10 +183,7 @@ pub(super) fn op_read_file_type(#[string] path: String) -> Result<String> {
}
#[deno_core::op2]
#[serde]
pub(super) fn op_read_dir(
#[string] path: String,
) -> Result<std::collections::HashMap<String, String>> {
pub(super) fn op_read_dir(#[string] path: String) -> Result<Map<String, &'static str>> {
let path = Path::new(&path);
if !path.is_dir() {
@@ -174,7 +193,7 @@ pub(super) fn op_read_dir(
let entries = std::fs::read_dir(path)
.map_err(|e| format!("Failed to read directory {}: {}", path.display(), e))?;
let mut result = std::collections::HashMap::new();
let mut result = HashMap::new();
for entry in entries {
let entry = entry.map_err(|e| format!("Failed to read directory entry: {}", e))?;
@@ -198,10 +217,10 @@ pub(super) fn op_read_dir(
"unknown"
};
result.insert(file_name, type_str.to_string());
result.insert(file_name, type_str);
}
Ok(result)
Ok(Map(result))
}
#[deno_core::op2]
@@ -255,12 +274,28 @@ pub(super) fn op_make_placeholder(#[string] output: String) -> String {
format!("/{}", encoded)
}
enum StringOrU32 {
String(String),
U32(u32),
}
impl<'a> ToV8<'a> for StringOrU32 {
type Error = Infallible;
fn to_v8<'i>(
self,
scope: &mut v8::PinScope<'a, 'i>,
) -> std::result::Result<v8::Local<'a, v8::Value>, Self::Error> {
match self {
Self::String(x) => x.to_v8(scope),
Self::U32(x) => x.to_v8(scope),
}
}
}
#[deno_core::op2]
#[serde]
pub(super) fn op_decode_span<Ctx: RuntimeContext>(
state: &mut OpState,
#[smi] span_id: u32,
) -> Result<serde_json::Value> {
) -> Map<&'static str, StringOrU32> {
let ctx: &Ctx = state.get_ctx();
let (source_id, range) = ctx.get_span(span_id as usize);
let source = ctx.get_source(source_id);
@@ -268,11 +303,11 @@ pub(super) fn op_decode_span<Ctx: RuntimeContext>(
let (line, column) = byte_offset_to_line_col(&source.src, start as usize);
Ok(serde_json::json!({
"file": source.get_name(),
"line": line,
"column": column
}))
Map(HashMap::from([
("file", StringOrU32::String(source.get_name())),
("line", StringOrU32::U32(line)),
("column", StringOrU32::U32(column)),
]))
}
fn byte_offset_to_line_col(content: &str, offset: usize) -> (u32, u32) {
@@ -294,14 +329,18 @@ fn byte_offset_to_line_col(content: &str, offset: usize) -> (u32, u32) {
(line, col)
}
#[derive(serde::Serialize)]
pub(super) struct ParsedHash {
hex: String,
algo: String,
mod private {
use deno_core::ToV8;
#[derive(ToV8)]
pub(super) struct ParsedHash {
pub(super) hex: String,
pub(super) algo: String,
}
}
use private::*;
#[deno_core::op2]
#[serde]
pub(super) fn op_parse_hash(
#[string] hash_str: String,
#[string] algo: Option<String>,
@@ -433,7 +472,7 @@ pub(super) fn op_to_file<Ctx: RuntimeContext>(
state: &mut OpState,
#[string] name: String,
#[string] contents: String,
#[serde] references: Vec<String>,
#[scoped] references: Vec<String>,
) -> Result<String> {
let ctx: &Ctx = state.get_ctx();
let store = ctx.get_store();
@@ -487,7 +526,6 @@ pub(super) fn op_get_env(#[string] key: String) -> Result<String> {
}
#[deno_core::op2]
#[serde]
pub(super) fn op_walk_dir(#[string] path: String) -> Result<Vec<(String, String)>> {
fn walk_recursive(
base: &Path,
@@ -549,7 +587,7 @@ pub(super) fn op_add_filtered_path<Ctx: RuntimeContext>(
#[string] name: Option<String>,
recursive: bool,
#[string] sha256: Option<String>,
#[serde] include_paths: Vec<String>,
#[scoped] include_paths: Vec<String>,
) -> Result<String> {
use nix_compat::nixhash::{HashAlgo, NixHash};
use sha2::{Digest, Sha256};
@@ -648,7 +686,6 @@ pub(super) fn op_add_filtered_path<Ctx: RuntimeContext>(
}
#[deno_core::op2]
#[serde]
pub(super) fn op_match(
state: &mut OpState,
#[string] regex: String,
@@ -673,7 +710,6 @@ pub(super) fn op_match(
}
#[deno_core::op2]
#[serde]
pub(super) fn op_split(
state: &mut OpState,
#[string] regex: String,
@@ -709,13 +745,30 @@ pub(super) fn op_split(
Ok(ret)
}
#[derive(serde::Serialize)]
#[serde(untagged)]
pub(super) enum SplitResult {
Text(String),
Captures(Vec<Option<String>>),
}
impl<'a> ToV8<'a> for SplitResult {
type Error = Infallible;
fn to_v8<'i>(
self,
scope: &mut v8::PinScope<'a, 'i>,
) -> std::result::Result<v8::Local<'a, v8::Value>, Self::Error> {
Ok(match self {
Self::Text(text) => {
let Ok(value) = text.to_v8(scope);
value
}
Self::Captures(captures) => {
let Ok(value) = captures.to_v8(scope);
value
}
})
}
}
pub(super) enum NixJsonValue {
Null,
Bool(bool),
@@ -836,34 +889,24 @@ pub(super) fn op_from_toml(#[string] toml_str: String) -> Result<NixJsonValue> {
toml_to_nix(parsed)
}
#[derive(serde::Deserialize)]
pub(super) struct FixedOutputInput {
#[serde(rename = "hashAlgo")]
hash_algo: String,
hash: String,
#[serde(rename = "hashMode")]
hash_mode: String,
}
mod scope {
use deno_core::{FromV8, ToV8};
#[derive(serde::Deserialize)]
pub(super) struct FinalizeDerivationInput {
name: String,
builder: String,
platform: String,
outputs: Vec<String>,
args: Vec<String>,
env: Vec<(String, String)>,
context: Vec<String>,
#[serde(rename = "fixedOutput")]
fixed_output: Option<FixedOutputInput>,
}
#[derive(FromV8)]
pub(super) struct FixedOutputInput {
pub(super) hash_algo: String,
pub(super) hash: String,
pub(super) hash_mode: String,
}
#[derive(serde::Serialize)]
pub(super) struct FinalizeDerivationOutput {
#[serde(rename = "drvPath")]
drv_path: String,
outputs: Vec<(String, String)>,
#[derive(ToV8)]
pub(super) struct FinalizeDerivationOutput {
// renamed to `drvPath` automatically
pub(super) drv_path: String,
pub(super) outputs: Vec<(String, String)>,
}
}
use scope::*;
fn output_path_name(drv_name: &str, output: &str) -> String {
if output == "out" {
@@ -874,10 +917,16 @@ fn output_path_name(drv_name: &str, output: &str) -> String {
}
#[deno_core::op2]
#[serde]
pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
state: &mut OpState,
#[serde] input: FinalizeDerivationInput,
#[string] name: String,
#[string] builder: String,
#[string] platform: String,
#[scoped] outputs: Vec<String>,
#[scoped] args: Vec<String>,
#[scoped] env: Vec<(String, String)>,
#[scoped] context: Vec<String>,
#[scoped] fixed_output: Option<FixedOutputInput>,
) -> Result<FinalizeDerivationOutput> {
use crate::derivation::{DerivationData, OutputInfo};
use crate::string_context::extract_input_drvs_and_srcs;
@@ -887,15 +936,15 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
let store_dir = store.get_store_dir().to_string();
let (input_drvs, input_srcs) =
extract_input_drvs_and_srcs(&input.context).map_err(NixRuntimeError::from)?;
extract_input_drvs_and_srcs(&context).map_err(NixRuntimeError::from)?;
let env: std::collections::BTreeMap<String, String> = input.env.into_iter().collect();
let env: BTreeMap<String, String> = env.into_iter().collect();
let drv_path;
let output_paths: Vec<(String, String)>;
if let Some(fixed) = &input.fixed_output {
let path_name = output_path_name(&input.name, "out");
if let Some(fixed) = &fixed_output {
let path_name = output_path_name(&name, "out");
let out_path = crate::runtime::ops::op_make_fixed_output_path_impl(
&store_dir,
&fixed.hash_algo,
@@ -910,7 +959,7 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
""
};
let mut final_outputs = std::collections::BTreeMap::new();
let mut final_outputs = BTreeMap::new();
final_outputs.insert(
"out".to_string(),
OutputInfo {
@@ -924,13 +973,13 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
final_env.insert("out".to_string(), out_path.clone());
let drv = DerivationData {
name: input.name.clone(),
name: name.clone(),
outputs: final_outputs,
input_drvs: input_drvs.clone(),
input_srcs: input_srcs.clone(),
platform: input.platform,
builder: input.builder,
args: input.args,
platform,
builder,
args,
env: final_env,
};
@@ -938,7 +987,7 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
let references = drv.collect_references();
drv_path = store
.add_text_to_store(&format!("{}.drv", input.name), &final_aterm, references)
.add_text_to_store(&format!("{}.drv", name), &final_aterm, references)
.map_err(|e| NixRuntimeError::from(format!("failed to write derivation: {}", e)))?;
let fixed_hash_fingerprint = format!(
@@ -952,8 +1001,7 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
output_paths = vec![("out".to_string(), out_path)];
} else {
let masked_outputs: std::collections::BTreeMap<String, OutputInfo> = input
.outputs
let masked_outputs: std::collections::BTreeMap<String, OutputInfo> = outputs
.iter()
.map(|o| {
(
@@ -968,18 +1016,18 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
.collect();
let mut masked_env = env.clone();
for output in &input.outputs {
for output in &outputs {
masked_env.insert(output.clone(), String::new());
}
let masked_drv = DerivationData {
name: input.name.clone(),
name: name.clone(),
outputs: masked_outputs,
input_drvs: input_drvs.clone(),
input_srcs: input_srcs.clone(),
platform: input.platform.clone(),
builder: input.builder.clone(),
args: input.args.clone(),
platform: platform.clone(),
builder: builder.clone(),
args: args.clone(),
env: masked_env,
};
@@ -1007,8 +1055,8 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
let mut final_env = env;
let mut result_output_paths = Vec::new();
for output_name in &input.outputs {
let path_name = output_path_name(&input.name, output_name);
for output_name in &outputs {
let path_name = output_path_name(&name, output_name);
let out_path = crate::nix_utils::make_store_path(
&store_dir,
&format!("output:{}", output_name),
@@ -1028,13 +1076,13 @@ pub(super) fn op_finalize_derivation<Ctx: RuntimeContext>(
}
let final_drv = DerivationData {
name: input.name,
name,
outputs: final_outputs,
input_drvs,
input_srcs,
platform: input.platform,
builder: input.builder,
args: input.args,
platform,
builder,
args,
env: final_env,
};
@@ -1161,21 +1209,21 @@ pub(super) fn op_hash_file(#[string] algo: String, #[string] path: String) -> Re
#[deno_core::op2]
#[string]
pub(super) fn op_convert_hash(#[serde] input: ConvertHashInput) -> Result<String> {
pub(super) fn op_convert_hash(
#[string] hash: &str,
#[string] algo: Option<String>,
#[string] format: &str,
) -> Result<String> {
use nix_compat::nixhash::{HashAlgo, NixHash};
let hash_algo = input
.hash_algo
.as_deref()
.and_then(|a| HashAlgo::from_str(a).ok());
let hash_algo = algo.as_deref().and_then(|a| HashAlgo::from_str(a).ok());
let hash = NixHash::from_str(&input.hash, hash_algo).map_err(|e| {
NixRuntimeError::from(format!("cannot convert hash '{}': {}", input.hash, e))
})?;
let hash = NixHash::from_str(hash, hash_algo)
.map_err(|e| NixRuntimeError::from(format!("cannot convert hash '{}': {}", hash, e)))?;
let bytes = hash.digest_as_bytes();
match input.to_format.as_str() {
match format {
"base16" => Ok(hex::encode(bytes)),
"nix32" | "base32" => Ok(nix_compat::nixbase32::encode(bytes)),
"base64" => {
@@ -1188,20 +1236,11 @@ pub(super) fn op_convert_hash(#[serde] input: ConvertHashInput) -> Result<String
})),
_ => Err(NixRuntimeError::from(format!(
"unknown hash format '{}'",
input.to_format
format
))),
}
}
#[derive(serde::Deserialize)]
pub(super) struct ConvertHashInput {
hash: String,
#[serde(rename = "hashAlgo")]
hash_algo: Option<String>,
#[serde(rename = "toHashFormat")]
to_format: String,
}
struct XmlCtx<'s> {
force_fn: v8::Local<'s, v8::Function>,
is_thunk: v8::Local<'s, v8::Symbol>,
@@ -1243,7 +1282,7 @@ impl<'s> XmlCtx<'s> {
struct XmlWriter {
buf: String,
context: Vec<String>,
drvs_seen: hashbrown::HashSet<String>,
drvs_seen: HashSet<String>,
}
impl XmlWriter {
@@ -1251,7 +1290,7 @@ impl XmlWriter {
Self {
buf: String::with_capacity(4096),
context: Vec::new(),
drvs_seen: hashbrown::HashSet::new(),
drvs_seen: HashSet::new(),
}
}
@@ -1742,7 +1781,6 @@ impl<'a> FromV8<'a> for ToXmlResult {
}
#[deno_core::op2]
#[serde]
pub(super) fn op_to_xml(#[scoped] value: ToXmlResult) -> (String, Vec<String>) {
(value.xml, value.context)
}