ronantakizawa/codereview-bench huggingface dataset:
Repository: GoogleContainerTools/jib
File: jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/StepsRunner.java (Java)

Code before:

  private <E> List<Future<E>> scheduleCallables(ImmutableList<? extends Callable<E>> callables) {
    return callables.stream().map(executorService::submit).collect(Collectors.toList());
  }

  private String computeArchitecture(String architecture) {
    if (architecture.equals("x86_64")) {
      return "amd64";
    } else if (architecture.equals("aarch64")) {
      return "arm64";
    }
    return architecture;
  }

  private Optional<Image> fetchBuiltImageForLocalBuild(String osType, String architecture)
      throws InterruptedException, ExecutionException {
    if (results.baseImagesAndBuiltImages.get().size() > 1) {
      LOGGER.warning(
          "Detected multi-platform configuration, only building the one that matches the local Docker Engine's os and architecture");
    }
    for (Map.Entry<Image, Future<Image>> imageEntry :
        results.baseImagesAndBuiltImages.get().entrySet()) {
      Image image = imageEntry.getValue().get();
      if (image.getArchitecture().equals(architecture) && image.getOs().equals(osType)) {
        return Optional.of(image);
      }
    }
    return Optional.empty();
  }
}


Review comment (refactor):
I see that they are already tested in `JibIntegrationTest`, but ideally I think the different cases should be tested in `StepsRunnerTest` since we don't have to run docker engine. I'll leave it to you to decide if the refactoring it needed. 

Code after:

  private <E> List<Future<E>> scheduleCallables(ImmutableList<? extends Callable<E>> callables) {
    return callables.stream().map(executorService::submit).collect(Collectors.toList());
  }

  @VisibleForTesting
  String normalizeArchitecture(String architecture) {
    // Create mapping based on https://docs.docker.com/engine/install/#supported-platforms
    if (architecture.equals("x86_64")) {
      return "amd64";
    } else if (architecture.equals("aarch64")) {
      return "arm64";
    }
    return architecture;
  }

  @VisibleForTesting
  Optional<Image> fetchBuiltImageForLocalBuild(String osType, String architecture)
      throws InterruptedException, ExecutionException {
    if (results.baseImagesAndBuiltImages.get().size() > 1) {
      LOGGER.warning(
          String.format(
              "Detected multi-platform configuration, only building the one that matches the local Docker Engine's os and architecture (%s/%s)",
              osType, architecture));
    }
    for (Map.Entry<Image, Future<Image>> imageEntry :
        results.baseImagesAndBuiltImages.get().entrySet()) {
      Image image = imageEntry.getValue().get();
      if (image.getArchitecture().equals(architecture) && image.getOs().equals(osType)) {
        return Optional.of(image);
      }
    }
    return Optional.empty();
  }
}
Repository: GraphiteEditor/Graphite
File: frontend/src/components/widgets/widgets.ts (TypeScript)

Code before:
	// `action` is used via `IconButtonWidget.callback`
	icon: string;
	size: number;
	gapAfter?: boolean;
}

// Popover Button
export interface PopoverButtonWidget {
	kind: "PopoverButton";
	tooltip?: string;
	callback?: Function;
	// popover: WidgetLayout;
	popover: { title: string; text: string }; // TODO: Replace this with a `WidgetLayout` like above for arbitrary layouts
	props: PopoverButtonProps;
}

export interface PopoverButtonProps {
	// `action` is used via `PopoverButtonWidget.callback`
	icon?: string;
}

// Number Input
export interface NumberInputWidget {
	kind: "NumberInput";
	tooltip?: string;
	path: string[];
	props: Omit<NumberInputProps, "value">;
}

export interface NumberInputProps {
	value: number;
	min?: number;
	max?: number;
	incrementBehavior?: boolean;
	incrementFactor?: number;
	isInteger?: boolean;
	unit?: string;
	unitIsHiddenWhenEditing?: boolean;
	displayDecimalPlaces?: number;
	label?: string;
	disabled?: boolean;
}

// Separator
export interface SeparatorWidget {
	kind: "Separator";
	props: SeparatorProps;
}

export interface SeparatorProps {
	direction?: SeparatorDirection;

Review comment (refactor):
I am worried that the word "path" is becoming very overloaded (it is both an SVG curve path as well as a layer path). I'm probably going to refactor layer paths in the backend from "path" to "layer_path" to avoid confusion. It would be good if we can similarly disambiguate here by calling this `optionPath` or something like that (pick what name you think is fitting).

Code after:
	// `action` is used via `IconButtonWidget.callback`
	icon: string;
	size: number;
	gapAfter?: boolean;
}

// Popover Button
export interface PopoverButtonWidget {
	kind: "PopoverButton";
	tooltip?: string;
	callback?: Function;
	// popover: WidgetLayout;
	popover: { title: string; text: string }; // TODO: Replace this with a `WidgetLayout` like above for arbitrary layouts
	props: PopoverButtonProps;
}

export interface PopoverButtonProps {
	// `action` is used via `PopoverButtonWidget.callback`
	icon?: string;
}

// Number Input
export interface NumberInputWidget {
	kind: "NumberInput";
	tooltip?: string;
	optionPath: string[];
	props: Omit<NumberInputProps, "value">;
}

export interface NumberInputProps {
	value: number;
	min?: number;
	max?: number;
	incrementBehavior?: boolean;
	incrementFactor?: number;
	isInteger?: boolean;
	unit?: string;
	unitIsHiddenWhenEditing?: boolean;
	displayDecimalPlaces?: number;
	label?: string;
	disabled?: boolean;
}

// Separator
export interface SeparatorWidget {
	kind: "Separator";
	props: SeparatorProps;
}

export interface SeparatorProps {
	direction?: SeparatorDirection;
Repository: GraphiteEditor/Graphite
File: node-graph/gcore/src/vector/generator_nodes.rs (Rust)

Code before:

use glam::DVec2;

#[derive(Debug, Clone, Copy)]
pub struct UnitCircleGenerator<Radius> {
	radius: Radius,
}

#[node_macro::node_fn(UnitCircleGenerator)]
fn unit_circle(_input: (), radius: f32) -> VectorData {
	let radius = radius.into();
	super::VectorData::from_subpath(Subpath::new_ellipse(DVec2::splat(radius * -1.), DVec2::splat(radius)))
}

#[derive(Debug, Clone, Copy)]
pub struct UnitElipseGenerator<RadiusX, RadiusY> {
	radius_x: RadiusX,
	radius_y: RadiusY,
}

#[node_macro::node_fn(UnitElipseGenerator)]
fn unit_elipse(_input: (), radius_x: f32, radius_y: f32) -> VectorData {
	let radius_x = radius_x.into();
	let radius_y: f64 = radius_y.into();
	let corner1 = DVec2::new(radius_x * -1., radius_y * -1.);
	let corner2: DVec2 = DVec2::new(radius_x, radius_y);
	super::VectorData::from_subpath(Subpath::new_ellipse(corner1, corner2))
}

#[derive(Debug, Clone, Copy)]
pub struct UnitRectangleGenerator<SizeX, SizeY> {
	size_x: SizeX,
	size_y: SizeY,
}

#[node_macro::node_fn(UnitRectangleGenerator)]
fn unit_square(_input: (), size_x: f32, size_y: f32) -> VectorData {
	let size_x = (size_x / 2.).into();
	let size_y = (size_y / 2.).into();
	let corner1 = DVec2::new(size_x * -1., size_y * -1.);
	let corner2 = DVec2::new(size_x, size_y);

	super::VectorData::from_subpaths(vec![Subpath::new_rect(corner1, corner2)])
}

#[derive(Debug, Clone, Copy)]
pub struct UnitPolygonGenerator<Points, Radius> {
	points: Points,
	radius: Radius,
}


Review comment (suggestion):
Could be simplified to:
```rs
let radius = DVec2::new(radius_x as f64, radius_y as f64);
let corner1 = -radius;
let corner2 = radius;
```

Code after:

use glam::DVec2;

#[derive(Debug, Clone, Copy)]
pub struct CircleGenerator<Radius> {
	radius: Radius,
}

#[node_macro::node_fn(CircleGenerator)]
fn circle_generator(_input: (), radius: f32) -> VectorData {
	let radius: f64 = radius.into();
	super::VectorData::from_subpath(Subpath::new_ellipse(DVec2::splat(-radius), DVec2::splat(radius)))
}

#[derive(Debug, Clone, Copy)]
pub struct EllipseGenerator<RadiusX, RadiusY> {
	radius_x: RadiusX,
	radius_y: RadiusY,
}

#[node_macro::node_fn(EllipseGenerator)]
fn ellipse_generator(_input: (), radius_x: f32, radius_y: f32) -> VectorData {
	let radius = DVec2::new(radius_x as f64, radius_y as f64);
	let corner1 = -radius;
	let corner2 = radius;
	super::VectorData::from_subpath(Subpath::new_ellipse(corner1, corner2))
}

#[derive(Debug, Clone, Copy)]
pub struct RectangleGenerator<SizeX, SizeY> {
	size_x: SizeX,
	size_y: SizeY,
}

#[node_macro::node_fn(RectangleGenerator)]
fn square_generator(_input: (), size_x: f32, size_y: f32) -> VectorData {
	let size = DVec2::new(size_x as f64, size_y as f64);
	let corner1 = -size / 2.;
	let corner2 = size / 2.;

	super::VectorData::from_subpaths(vec![Subpath::new_rect(corner1, corner2)])
}

#[derive(Debug, Clone, Copy)]
pub struct RegularPolygonGenerator<Points, Radius> {
	points: Points,
	radius: Radius,
}

#[node_macro::node_fn(RegularPolygonGenerator)]
fn regular_polygon_generator(_input: (), points: u32, radius: f32) -> VectorData {
Repository: GraphiteEditor/Graphite
File: node-graph/node-macro/src/codegen.rs (Rust)

Code before:
				Some(ty) => quote!(Some(concrete!(#ty))),
				_ => quote!(None),
			},
			_ => quote!(None),
		})
		.collect();

	let number_min_values: Vec<_> = fields
		.iter()
		.map(|field| match field {
			ParsedField::Regular { number_min: Some(number_min), .. } => quote!(Some(#number_min)),
			_ => quote!(None),
		})
		.collect();
	let number_max_values: Vec<_> = fields
		.iter()
		.map(|field| match field {
			ParsedField::Regular { number_max: Some(number_max), .. } => quote!(Some(#number_max)),
			_ => quote!(None),
		})
		.collect();
	let number_mode_range_values: Vec<_> = fields
		.iter()
		.map(|field| match field {
			ParsedField::Regular {
				number_mode_range: Some(number_mode_range),
				..
			} => quote!(Some(#number_mode_range)),
			_ => quote!(None),
		})
		.collect();

	let exposed: Vec<_> = fields
		.iter()
		.map(|field| match field {
			ParsedField::Regular { exposed, .. } => quote!(#exposed),
			_ => quote!(true),
		})
		.collect();

	let eval_args = fields.iter().map(|field| match field {
		ParsedField::Regular { pat_ident, .. } => {
			let name = &pat_ident.ident;
			quote! { let #name = self.#name.eval(__input.clone()).await; }
		}
		ParsedField::Node { pat_ident, .. } => {
			let name = &pat_ident.ident;
			quote! { let #name = &self.#name; }
		}
	});


Review comment (suggestion):
We have the hard and soft cases of these match arms both producing the same result. Is that intentional and sensible here? Assuming so, they should also perhaps be combined, replacing `None` with `_` and using ` | ` to put them on the same line.

Code after:
				Some(ty) => quote!(Some(concrete!(#ty))),
				_ => quote!(None),
			},
			_ => quote!(None),
		})
		.collect();

	let number_min_values: Vec<_> = fields
		.iter()
		.map(|field| match field {
			ParsedField::Regular { number_soft_min, number_hard_min, .. } => match (number_soft_min, number_hard_min) {
				(Some(soft_min), _) => quote!(Some(#soft_min)),
				(None, Some(hard_min)) => quote!(Some(#hard_min)),
				(None, None) => quote!(None),
			},
			_ => quote!(None),
		})
		.collect();
	let number_max_values: Vec<_> = fields
		.iter()
		.map(|field| match field {
			ParsedField::Regular { number_soft_max, number_hard_max, .. } => match (number_soft_max, number_hard_max) {
				(Some(soft_max), _) => quote!(Some(#soft_max)),
				(None, Some(hard_max)) => quote!(Some(#hard_max)),
				(None, None) => quote!(None),
			},
			_ => quote!(None),
		})
		.collect();
	let number_mode_range_values: Vec<_> = fields
		.iter()
		.map(|field| match field {
			ParsedField::Regular {
				number_mode_range: Some(number_mode_range),
				..
			} => quote!(Some(#number_mode_range)),
			_ => quote!(None),
		})
		.collect();

	let exposed: Vec<_> = fields
		.iter()
		.map(|field| match field {
			ParsedField::Regular { exposed, .. } => quote!(#exposed),
			_ => quote!(true),
		})
		.collect();

	let eval_args = fields.iter().map(|field| match field {
		ParsedField::Regular { pat_ident, .. } => {
			let name = &pat_ident.ident;
Repository: GraphiteEditor/Graphite
File: editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs (Rust)

Code before:
				let size = ipp.viewport_bounds.size().as_uvec2();

				let [a, b, c, d, e, f] = DAffine2::from_scale(DVec2::splat(device_pixel_ratio)).to_cols_array();
				let _ = context.set_transform(a, b, c, d, e, f);
				context.clear_rect(0., 0., ipp.viewport_bounds.size().x, ipp.viewport_bounds.size().y);
				let _ = context.reset_transform();

				if overlays_visible {
					responses.add(DocumentMessage::GridOverlays(OverlayContext {
						render_context: context.clone(),
						size: size.as_dvec2(),
						device_pixel_ratio,
					}));
					for provider in &self.overlay_providers {
						responses.add(provider(OverlayContext {
							render_context: context.clone(),
							size: size.as_dvec2(),
							device_pixel_ratio,
						}));
					}
				}
			}
			#[cfg(not(target_arch = "wasm32"))]
			OverlaysMessage::Draw => {
				warn!(
					"Cannot render overlays on non-Wasm targets.\n{responses:?} {overlays_visible} {device_pixel_ratio} {ipp:?} {:?} {:?}",
					self.canvas, self.context
				);
			}
			OverlaysMessage::AddProvider(message) => {
				self.overlay_providers.insert(message);
			}
			OverlaysMessage::RemoveProvider(message) => {
				self.overlay_providers.remove(&message);
			}
		}
	}

	advertise_actions!(OverlaysMessage;);
}


Review comment (suggestion):
```suggestion
					"Cannot render overlays on non-Wasm targets.\n{responses:?} {overlays_visible} {ipp:?} {:?} {:?}",
```

Code after:
				let size = ipp.viewport_bounds.size().as_uvec2();

				let [a, b, c, d, e, f] = DAffine2::from_scale(DVec2::splat(device_pixel_ratio)).to_cols_array();
				let _ = context.set_transform(a, b, c, d, e, f);
				context.clear_rect(0., 0., ipp.viewport_bounds.size().x, ipp.viewport_bounds.size().y);
				let _ = context.reset_transform();

				if overlays_visible {
					responses.add(DocumentMessage::GridOverlays(OverlayContext {
						render_context: context.clone(),
						size: size.as_dvec2(),
						device_pixel_ratio,
					}));
					for provider in &self.overlay_providers {
						responses.add(provider(OverlayContext {
							render_context: context.clone(),
							size: size.as_dvec2(),
							device_pixel_ratio,
						}));
					}
				}
			}
			#[cfg(not(target_arch = "wasm32"))]
			OverlaysMessage::Draw => {
				warn!(
					"Cannot render overlays on non-Wasm targets.\n{responses:?} {overlays_visible} {ipp:?} {:?} {:?}",
					self.canvas, self.context
				);
			}
			OverlaysMessage::AddProvider(message) => {
				self.overlay_providers.insert(message);
			}
			OverlaysMessage::RemoveProvider(message) => {
				self.overlay_providers.remove(&message);
			}
		}
	}

	advertise_actions!(OverlaysMessage;);
}
Repository: GraphiteEditor/Graphite
File: editor/src/messages/portfolio/document/utility_types/misc.rs (Rust)

Code before:
		}
	}
}

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
#[serde(default)]
pub struct GridSnapping {
	pub origin: DVec2,
	pub grid_type: GridType,
	pub rectangular_spacing: DVec2,
	pub isometric_y_spacing: f64,
	pub isometric_angle_a: f64,
	pub isometric_angle_b: f64,
	pub grid_color: Color,
	pub dot_display: bool,
}

impl Default for GridSnapping {
	fn default() -> Self {
		Self {
			origin: DVec2::ZERO,
			grid_type: Default::default(),
			rectangular_spacing: DVec2::ONE,
			isometric_y_spacing: 1.0,
			isometric_angle_a: 30.0,
			isometric_angle_b: 30.0,
			grid_color: Color::from_rgb_str(COLOR_OVERLAY_GRAY.strip_prefix('#').unwrap()).unwrap(),
			dot_display: false,
		}
	}
}

impl GridSnapping {
	// Double grid size until it takes up at least 10px.
	pub fn compute_rectangle_spacing(mut size: DVec2, navigation: &PTZ) -> Option<DVec2> {
		let mut iterations = 0;
		size = size.abs();
		while (size * navigation.zoom()).cmplt(DVec2::splat(10.)).any() {
			if iterations > 100 {
				return None;
			}
			size *= 2.;
			iterations += 1;
		}
		Some(size)
	}

	// Double grid size until it takes up at least 10px.
	pub fn compute_isometric_multiplier(length: f64, divisor: f64, navigation: &PTZ) -> Option<f64> {
		let length = length.abs();
		let mut iterations = 0;

Review comment (suggestion):
```suggestion
			isometric_y_spacing: 1.,
			isometric_angle_a: 30.,
			isometric_angle_b: 30.,
```

Code after:
		}
	}
}

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
#[serde(default)]
pub struct GridSnapping {
	pub origin: DVec2,
	pub grid_type: GridType,
	pub rectangular_spacing: DVec2,
	pub isometric_y_spacing: f64,
	pub isometric_angle_a: f64,
	pub isometric_angle_b: f64,
	pub grid_color: Color,
	pub dot_display: bool,
}

impl Default for GridSnapping {
	fn default() -> Self {
		Self {
			origin: DVec2::ZERO,
			grid_type: Default::default(),
			rectangular_spacing: DVec2::ONE,
			isometric_y_spacing: 1.,
			isometric_angle_a: 30.,
			isometric_angle_b: 30.,
			grid_color: Color::from_rgb_str(COLOR_OVERLAY_GRAY.strip_prefix('#').unwrap()).unwrap(),
			dot_display: false,
		}
	}
}

impl GridSnapping {
	// Double grid size until it takes up at least 10px.
	pub fn compute_rectangle_spacing(mut size: DVec2, navigation: &PTZ) -> Option<DVec2> {
		let mut iterations = 0;
		size = size.abs();
		while (size * navigation.zoom()).cmplt(DVec2::splat(10.)).any() {
			if iterations > 100 {
				return None;
			}
			size *= 2.;
			iterations += 1;
		}
		Some(size)
	}

	// Double grid size until it takes up at least 10px.
	pub fn compute_isometric_multiplier(length: f64, divisor: f64, navigation: &PTZ) -> Option<f64> {
		let length = length.abs();
		let mut iterations = 0;
Repository: GraphiteEditor/Graphite
File: node-graph/gmath-nodes/src/lib.rs (Rust)

Code before:
#[node_macro::node(category("Value"))]
fn gradient_value(_: impl Ctx, _primary: (), gradient: GradientStops) -> GradientStops {
	gradient
}

/// Constructs a string value which may be set to any plain text.
#[node_macro::node(category("Value"))]
fn string_value(_: impl Ctx, _primary: (), string: TextArea) -> String {
	string
}

#[node_macro::node(category("Math: Vector"))]
fn dot_product(_: impl Ctx, vector_a: DVec2, vector_b: DVec2) -> f64 {
	vector_a.dot(vector_b)
}

/// Gets the length or magnitude of a vector.
#[node_macro::node(category("Math: Vector"))]
fn length(_: impl Ctx, vector: DVec2) -> f64 {
	vector.length()
}

/// Scales the input vector to unit length while preserving it's direction. This is equivalent to dividing the input vector by it's own magnitude.
#[node_macro::node(category("Math: Vector"))]
fn normalize(_: impl Ctx, vector: DVec2) -> DVec2 {
	vector.normalize()
}

#[cfg(test)]
mod test {
	use super::*;
	use graphene_core::Node;
	use graphene_core::generic::FnNode;

	#[test]
	pub fn dot_product_function() {
		let vector_a = DVec2::new(1., 2.);
		let vector_b = DVec2::new(3., 4.);
		assert_eq!(dot_product((), vector_a, vector_b), 11.);
	}

	#[test]
	pub fn length_function() {
		let vector = DVec2::new(3., 4.);
		assert_eq!(length((), vector), 5.);
	}

	#[test]
	fn test_basic_expression() {
		let result = math((), 0., "2 + 2".to_string(), 0.);
		assert_eq!(result, 4.);

Review comment (bug):
The `normalize` function can cause a crash if the length is zero. Consider using `normalize_or_zero`.

Code after:
#[node_macro::node(category("Value"))]
fn gradient_value(_: impl Ctx, _primary: (), gradient: GradientStops) -> GradientStops {
	gradient
}

/// Constructs a string value which may be set to any plain text.
#[node_macro::node(category("Value"))]
fn string_value(_: impl Ctx, _primary: (), string: TextArea) -> String {
	string
}

#[node_macro::node(category("Math: Vector"))]
fn dot_product(_: impl Ctx, vector_a: DVec2, vector_b: DVec2) -> f64 {
	vector_a.dot(vector_b)
}

/// Gets the length or magnitude of a vector.
#[node_macro::node(category("Math: Vector"))]
fn length(_: impl Ctx, vector: DVec2) -> f64 {
	vector.length()
}

/// Scales the input vector to unit length while preserving it's direction. This is equivalent to dividing the input vector by it's own magnitude.
///
/// Returns zero when the input vector is zero.
#[node_macro::node(category("Math: Vector"))]
fn normalize(_: impl Ctx, vector: DVec2) -> DVec2 {
	vector.normalize_or_zero()
}

#[cfg(test)]
mod test {
	use super::*;
	use graphene_core::Node;
	use graphene_core::generic::FnNode;

	#[test]
	pub fn dot_product_function() {
		let vector_a = DVec2::new(1., 2.);
		let vector_b = DVec2::new(3., 4.);
		assert_eq!(dot_product((), vector_a, vector_b), 11.);
	}

	#[test]
	pub fn length_function() {
		let vector = DVec2::new(3., 4.);
		assert_eq!(length((), vector), 5.);
	}

	#[test]
	fn test_basic_expression() {
Repository: GraphiteEditor/Graphite
File: desktop/src/main.rs (Rust)

Code before:
use std::fmt::Debug;
use std::process::exit;
use std::time::Instant;

use tracing_subscriber::EnvFilter;
use winit::event_loop::EventLoop;

mod cef;
use cef::{Setup, WindowSize};

mod render;
use render::WgpuContext;

mod app;
use app::WinitApp;

mod dirs;

#[derive(Debug)]
pub(crate) enum CustomEvent {
	UiUpdate((wgpu::Texture, u32, u32)),
	ScheduleBrowserWork(Instant),
}

fn main() {
	tracing_subscriber::fmt().with_env_filter(EnvFilter::from_default_env()).init();

	let cef_context = match cef::Context::<Setup>::new() {
		Ok(c) => c,
		Err(cef::SetupError::Subprocess) => exit(0),
		Err(cef::SetupError::SubprocessFailed(t)) => {
			tracing::error!("Subprocess of type {t} failed");
			exit(1);
		}
	};

	let event_loop = EventLoop::<CustomEvent>::with_user_event().build().unwrap();

	let (window_size_sender, window_size_receiver) = std::sync::mpsc::channel();

	let wgpu_context = pollster::block_on(WgpuContext::new());
	let cef_context = match cef_context.init(cef::CefHandler::new(window_size_receiver, event_loop.create_proxy(), wgpu_context.clone())) {
		Ok(c) => c,
		Err(cef::InitError::InitializationFailed) => {
			tracing::error!("Cef initialization failed");
			exit(1);

Review comment (suggestion):
Could be something like:

```
UiUpdate {
  Texture, 
  width,
  height,
}
```

Code after:
use std::fmt::Debug;
use std::process::exit;
use std::time::Instant;

use tracing_subscriber::EnvFilter;
use winit::event_loop::EventLoop;

mod cef;
use cef::{Setup, WindowSize};

mod render;
use render::WgpuContext;

mod app;
use app::WinitApp;

mod dirs;

#[derive(Debug)]
pub(crate) enum CustomEvent {
	UiUpdate(wgpu::Texture),
	ScheduleBrowserWork(Instant),
}

fn main() {
	tracing_subscriber::fmt().with_env_filter(EnvFilter::from_default_env()).init();

	let cef_context = match cef::Context::<Setup>::new() {
		Ok(c) => c,
		Err(cef::SetupError::Subprocess) => exit(0),
		Err(cef::SetupError::SubprocessFailed(t)) => {
			tracing::error!("Subprocess of type {t} failed");
			exit(1);
		}
	};

	let event_loop = EventLoop::<CustomEvent>::with_user_event().build().unwrap();

	let (window_size_sender, window_size_receiver) = std::sync::mpsc::channel();

	let wgpu_context = futures::executor::block_on(WgpuContext::new());
	let cef_context = match cef_context.init(cef::CefHandler::new(window_size_receiver, event_loop.create_proxy(), wgpu_context.clone())) {
		Ok(c) => c,
		Err(cef::InitError::InitializationFailed) => {
			tracing::error!("Cef initialization failed");
			exit(1);