Skip to content

Commit

Permalink
Serializes libraries without the binary
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed Oct 6, 2023
1 parent 3b0ec44 commit 9274f21
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 3 deletions.
1 change: 1 addition & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[env]
LLVM_PREFIX = { value = "lib/llvm", relative = true }
NITRO_FFI = { value = "lib/ffi/lib", relative = true }
ZSTD_PREFIX = { value = "lib/zstd", relative = true }
6 changes: 6 additions & 0 deletions stage0/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ fn main() {
println!("cargo:rustc-link-lib=LLVMSupport");
println!("cargo:rustc-link-lib=LLVMDemangle");

// Link zstd.
let zstd = std::env::var("ZSTD_PREFIX").unwrap();

println!("cargo:rustc-link-search={}/lib", zstd);
println!("cargo:rustc-link-lib=zstd");

// Link C++.
match std::env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() {
"linux" => {
Expand Down
36 changes: 36 additions & 0 deletions stage0/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ extern "C" {
pub fn llvm_builder_append_block(ib: *mut LlvmBuilder, bb: *mut LlvmBlock);
pub fn llvm_builder_ret_void(ib: *mut LlvmBuilder) -> *mut LlvmReturn;
pub fn llvm_builder_ret(ib: *mut LlvmBuilder, v: *mut LlvmValue) -> *mut LlvmReturn;
pub fn ZSTD_createCStream() -> *mut ZstdContex;
pub fn ZSTD_freeCStream(zcs: *mut ZstdContex) -> usize;
pub fn ZSTD_compressStream2(
cctx: *mut ZstdContex,
output: *mut ZSTD_outBuffer,
input: *mut ZSTD_inBuffer,
endOp: ZSTD_EndDirective,
) -> usize;
pub fn ZSTD_CStreamInSize() -> usize;
pub fn ZSTD_CStreamOutSize() -> usize;
pub fn ZSTD_isError(code: usize) -> u32;
pub fn ZSTD_getErrorName(code: usize) -> *const c_char;
}

pub struct LlvmTarget(());
Expand All @@ -72,3 +84,27 @@ pub struct LlvmConstInt(());
pub struct LlvmBlock(());
pub struct LlvmBuilder(());
pub struct LlvmReturn(());
pub struct ZstdContex(());

#[repr(C)]
#[allow(non_camel_case_types)]
pub struct ZSTD_inBuffer {
pub src: *const u8,
pub size: usize,
pub pos: usize,
}

#[repr(C)]
#[allow(non_camel_case_types)]
pub struct ZSTD_outBuffer {
pub dst: *mut u8,
pub size: usize,
pub pos: usize,
}

#[repr(C)]
#[allow(non_camel_case_types)]
pub enum ZSTD_EndDirective {
ZSTD_e_continue = 0,
ZSTD_e_end = 2,
}
1 change: 1 addition & 0 deletions stage0/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod ffi;
mod lexer;
mod pkg;
mod project;
mod zstd;

fn main() -> ExitCode {
// Parse arguments.
Expand Down
8 changes: 8 additions & 0 deletions stage0/src/pkg/dep.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::{PackageName, PackageVersion};
use std::hash::{Hash, Hasher};
use std::io::Write;

/// An object for resolving package dependencies.
pub struct DependencyResolver {}
Expand All @@ -16,6 +17,13 @@ pub struct Dependency {
version: PackageVersion,
}

impl Dependency {
pub fn serialize<W: Write>(&self, mut w: W) -> Result<(), std::io::Error> {
w.write_all(&self.name.to_bin())?;
w.write_all(&self.version.to_bin().to_be_bytes())
}
}

impl PartialEq for Dependency {
fn eq(&self, other: &Self) -> bool {
self.name == other.name && self.version.major() == other.version.major()
Expand Down
47 changes: 44 additions & 3 deletions stage0/src/pkg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ pub use self::meta::*;
pub use self::target::*;
pub use self::ty::*;

use crate::zstd::ZstdWriter;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::Write;
use std::io::{Seek, SeekFrom, Write};
use std::path::{Path, PathBuf};
use std::time::SystemTime;
use thiserror::Error;
Expand All @@ -31,7 +32,8 @@ impl Package {
const ENTRY_NAME: u8 = 1;
const ENTRY_VERSION: u8 = 2;
const ENTRY_DATE: u8 = 3;
const ENTRY_LIB: u8 = 4;
const ENTRY_EXE: u8 = 4;
const ENTRY_LIB: u8 = 5;

pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, PackageOpenError> {
todo!()
Expand Down Expand Up @@ -80,7 +82,46 @@ impl Package {
.to_be_bytes(),
)?;

// End of meta data.
// Write libraries
for (target, lib) in &self.libs {
// Write the target.
file.write_all(&[Self::ENTRY_LIB])?;
file.write_all(target.id().as_bytes())?;

// Write dependencies.
let count = TryInto::<u16>::try_into(lib.deps.len())
.unwrap()
.to_be_bytes();

file.write_all(&count)?;

for dep in &lib.deps {
dep.serialize(&mut file)?;
}

// Create a placeholder for binary length.
let lenoff = file.stream_position().unwrap();

file.write_all(&[0; 4])?;

// Write the library.
let mut writer = ZstdWriter::new(&mut file);

lib.bin.serialize(&mut writer)?;
writer.flush()?;

drop(writer);

// Write library length.
let cur = file.stream_position().unwrap();
let len: u32 = (cur - lenoff - 4).try_into().unwrap();

file.seek(SeekFrom::Start(lenoff)).unwrap();
file.write_all(&len.to_be_bytes())?;
file.seek(SeekFrom::Start(cur)).unwrap();
}

// End of entries.
file.write_all(&[Self::ENTRY_END])?;

Ok(())
Expand Down
123 changes: 123 additions & 0 deletions stage0/src/zstd/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use crate::ffi::{
ZSTD_CStreamInSize, ZSTD_CStreamOutSize, ZSTD_EndDirective, ZSTD_compressStream2,
ZSTD_createCStream, ZSTD_freeCStream, ZSTD_getErrorName, ZSTD_inBuffer, ZSTD_isError,
ZSTD_outBuffer, ZstdContex,
};
use std::cmp::min;
use std::ffi::CStr;
use std::io::{Error, ErrorKind, Write};
use std::ptr::null;

/// An implementation of [`Write`] that compress the data with zstd before writing to the underlying
/// [`Write`].
pub struct ZstdWriter<D> {
cx: *mut ZstdContex,
buf: Vec<u8>,
block: usize,
dest: D,
}

impl<D> ZstdWriter<D> {
pub fn new(dest: D) -> Self {
Self {
cx: unsafe { ZSTD_createCStream() },
buf: vec![0; unsafe { ZSTD_CStreamOutSize() }],
block: unsafe { ZSTD_CStreamInSize() },
dest,
}
}

fn error_name(code: usize) -> &'static str {
unsafe { CStr::from_ptr(ZSTD_getErrorName(code)).to_str().unwrap() }
}
}

impl<D> Drop for ZstdWriter<D> {
fn drop(&mut self) {
assert_eq!(unsafe { ZSTD_isError(ZSTD_freeCStream(self.cx)) }, 0);
}
}

impl<D: Write> Write for ZstdWriter<D> {
fn write(&mut self, mut buf: &[u8]) -> std::io::Result<usize> {
let mut written = 0;

while !buf.is_empty() {
// Setup input.
let mut input = ZSTD_inBuffer {
src: buf.as_ptr(),
size: min(buf.len(), self.block),
pos: 0,
};

// Setup output.
let mut output = ZSTD_outBuffer {
dst: self.buf.as_mut_ptr(),
size: self.buf.len(),
pos: 0,
};

// Compress.
let remain = unsafe {
ZSTD_compressStream2(
self.cx,
&mut output,
&mut input,
ZSTD_EndDirective::ZSTD_e_continue,
)
};

if unsafe { ZSTD_isError(remain) } != 0 {
return Err(Error::new(ErrorKind::Other, Self::error_name(remain)));
}

// Write the destination.
self.dest.write_all(&self.buf[..output.pos])?;

// Move to next data.
written += input.pos;
buf = &buf[input.pos..];
}

Ok(written)
}

fn flush(&mut self) -> std::io::Result<()> {
loop {
// Setup input.
let mut input = ZSTD_inBuffer {
src: null(),
size: 0,
pos: 0,
};

// Setup output.
let mut output = ZSTD_outBuffer {
dst: self.buf.as_mut_ptr(),
size: self.buf.len(),
pos: 0,
};

// Flush.
let remain = unsafe {
ZSTD_compressStream2(
self.cx,
&mut output,
&mut input,
ZSTD_EndDirective::ZSTD_e_end,
)
};

if unsafe { ZSTD_isError(remain) } != 0 {
break Err(Error::new(ErrorKind::Other, Self::error_name(remain)));
}

// Write the destination.
self.dest.write_all(&self.buf[..output.pos])?;

if remain == 0 {
break Ok(());
}
}
}
}

0 comments on commit 9274f21

Please sign in to comment.